bug(w.l.fixed): Fix drawing to infinite available space

With the overflow layout, it is now possible to allow theoretically
infinite space for widgets to draw into. The `fixed` layout was broken
for this use case.

To determine the total amount of space used by its child widgets, the
`fixed` layout would subtract their size from the total available space
during `:fit` and keep that as a "remaining size" variable.
However, `Infinity - x == Infinity` (when `x < Infinity`).

So `:fit` would always end up with a calculation `needed_size =
available_size - size_left` or `x = Infinity - Infinity`, which is `0`.
So with infinite space available, the `fixed` layout would actually
report a size of `0`.

See also discussion at
https://github.com/awesomeWM/awesome/pull/3309#issuecomment-997191875

Signed-off-by: Lucas Schwiderski <lucas@lschwiderski.de>
This commit is contained in:
Lucas Schwiderski 2021-12-18 14:20:48 +01:00
parent 52460a3317
commit 51424b5da9
No known key found for this signature in database
GPG Key ID: AA12679AAA6DF4D8
2 changed files with 59 additions and 36 deletions

View File

@ -333,35 +333,23 @@ end
-- @param orig_width The available width.
-- @param orig_height The available height.
function fixed:fit(context, orig_width, orig_height)
local width_left, height_left = orig_width, orig_height
local spacing = self._private.spacing or 0
local widgets_nr = #self._private.widgets
local is_y = self._private.dir == "y"
local used_max = 0
-- when no widgets exist the function can be called with orig_width or
-- orig_height equal to nil. Exit early in this case.
if widgets_nr == 0 then
local widgets = self._private.widgets
local num_widgets = #widgets
-- Return early if there are no widgets to draw
if num_widgets < 1 then
return 0, 0
end
for k, v in pairs(self._private.widgets) do
local w, h = base.fit_widget(self, context, v, width_left, height_left)
local max
local width_left, height_left = orig_width, orig_height
local used_in_dir, used_max = 0, 0
local is_y = self._private.dir == "y"
local spacing = self._private.spacing or 0
if is_y then
max = w
height_left = height_left - h
else
max = h
width_left = width_left - w
end
for k, v in ipairs(widgets) do
-- Keep in mind that `spacing` may be negative to create overlap
if k > 1 and spacing ~= 0 then
used_in_dir = used_in_dir + spacing
if max > used_max then
used_max = max
end
if k < widgets_nr then
if is_y then
height_left = height_left - spacing
else
@ -369,25 +357,45 @@ function fixed:fit(context, orig_width, orig_height)
end
end
if width_left <= 0 or height_left <= 0 then
-- this complicated two lines determine whether we're out-of-space
-- because of spacing, or if the last widget doesn't fit in
if is_y then
height_left = k < widgets_nr and height_left + spacing or height_left
height_left = height_left < 0 and 0 or height_left
else
width_left = k < widgets_nr and width_left + spacing or width_left
width_left = width_left < 0 and 0 or width_left
local w, h = base.fit_widget(self, context, v, width_left, height_left)
-- Determine if the widget still fits
local is_enough
if is_y then
is_enough = h > 0 and height_left >= h
if is_enough then
used_max = math.max(used_max, w)
used_in_dir = used_in_dir + h
height_left = height_left - h
end
else
is_enough = w > 0 and width_left >= w
if is_enough then
used_max = math.max(used_max, h)
used_in_dir = used_in_dir + w
width_left = width_left - w
end
end
if not is_enough then
-- Remove previous spacing if there was not enough space
-- to add the current widget
used_in_dir = used_in_dir - spacing
break
elseif width_left <= 0 or height_left <= 0 then
break
end
end
if is_y then
return used_max, orig_height - height_left
return used_max, used_in_dir
else
return used_in_dir, used_max
end
return orig_width - width_left, used_max
end
function fixed:reset()

View File

@ -198,6 +198,21 @@ describe("wibox.layout.overflow", function()
layout:reset()
assert.is.same({}, layout:get_children())
end)
it("can draw `wibox.layout.fixed` as child", function()
local fixed = require("wibox.layout.fixed")
local w1 = utils.widget_stub(10, 10)
local w2 = utils.widget_stub(10, 10)
local lfixed = fixed.vertical()
lfixed:add(w1)
lfixed:add(w2)
layout:add(lfixed)
assert.widget_layout(layout, { 100, 100 }, {
p(lfixed, 0, 0, 100, 20),
})
end)
end)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80