fixed: Try to handle zero sized widgets again.

The newly changed code doesn't handle this well:

    local w = wibox.widget {
        {
            --add anything here
            widget = wibox.layout.fixed.horizontal
        },
        widget = wibox.layout.fixed.horizontal,
    }

This will cause the "inner" fixed layout to have the minimum size
it supports. In that case, if the last widget has "no size" because
it supports up to 0x0, then it isn't added to the layout.

This was done "on purpose" because if there is a spacing, then `:fit`
would have returned a size "too small" because the last spacing area
would be (correctly) missing.

But if the zero sized widget isn't added to the layout, then it's size
isn't tracker. So if it emits a layout_changed signal, nothing catches
it.

The "fix" is rather hacky and probably a little incorrect. It rely
on the behavior of `:fit()` to avoid adding the "wrong" widgets to
the layout, which is fragile.

However, I don't have a better idea.
This commit is contained in:
Emmanuel Lepage Vallee 2021-05-31 01:19:25 -07:00
parent fedc7dc69d
commit 83c31f948b
2 changed files with 40 additions and 6 deletions

View File

@ -33,39 +33,71 @@ function fixed:layout(context, width, height)
spacing_widget = spacing ~= 0 and self._private.spacing_widget or nil
for k, v in pairs(self._private.widgets) do
local w, h = width - x, height - y
local w, h, local_spacing = width - x, height - y, spacing
-- Some widget might be zero sized either because this is their
-- minimum space or just because they are really empty. In this case,
-- they must still be added to the layout. Otherwise, if their size
-- change and this layout is resizable, they are lost "forever" until
-- a full relayout is called on this fixed layout object.
local zero = false
if is_y then
if k ~= widgets_nr or not self._private.fill_space then
h = select(2, base.fit_widget(self, context, v, w, h))
zero = h == 0
end
if y - spacing >= height then
-- pop the spacing widget added in previous iteration if used
if spacing_widget then
table.remove(result)
-- Avoid adding zero-sized widgets at an out-of-bound
-- position.
y = y - spacing
end
-- Never display "random" widgets as soon as a non-zero sized
-- one doesn't fit.
if not zero then
break
end
break
end
else
if k ~= widgets_nr or not self._private.fill_space then
w = select(1, base.fit_widget(self, context, v, w, h))
zero = w == 0
end
if x - spacing >= width then
-- pop the spacing widget added in previous iteration if used
if spacing_widget then
table.remove(result)
-- Avoid adding zero-sized widgets at an out-of-bound
-- position.
x = x - spacing
end
-- Never display "random" widgets as soon as a non-zero sized
-- one doesn't fit.
if not zero then
break
end
break
end
end
-- Place widget
if zero then
local_spacing = 0
end
-- Place widget, even if it has zero width/height. Otherwise
-- any layout change for zero-sized widget would become invisible.
table.insert(result, base.place_widget_at(v, x, y, w, h))
x = is_x and x + w + spacing or x
y = is_y and y + h + spacing or y
x = is_x and x + w + local_spacing or x
y = is_y and y + h + local_spacing or y
-- Add the spacing widget (if needed)
if k < widgets_nr and spacing_widget then

View File

@ -78,6 +78,7 @@ describe("wibox.layout.fixed", function()
assert.widget_layout(layout, { 100, 20 }, {
p(first, 0, 0, 100, 10),
p(second, 0, 10, 100, 10),
p(third, 0, 20, 100, 0),
})
end)
end)
@ -121,6 +122,7 @@ describe("wibox.layout.fixed", function()
p(first, 0, 0, 100, 10),
p(spacing_widget, 0, 10, 100, 10),
p(second, 0, 20, 100, 15),
p(third, 0, 35, 100, 0),
})
end)
end)