From 51424b5da9fd436df8e0c33cb98f45aa03e8092a Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Sat, 18 Dec 2021 14:20:48 +0100 Subject: [PATCH] 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 --- lib/wibox/layout/fixed.lua | 80 ++++++++++++++++------------- spec/wibox/layout/overflow_spec.lua | 15 ++++++ 2 files changed, 59 insertions(+), 36 deletions(-) diff --git a/lib/wibox/layout/fixed.lua b/lib/wibox/layout/fixed.lua index bd76c3207..acfee8d6a 100644 --- a/lib/wibox/layout/fixed.lua +++ b/lib/wibox/layout/fixed.lua @@ -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() diff --git a/spec/wibox/layout/overflow_spec.lua b/spec/wibox/layout/overflow_spec.lua index d69252d47..a4df6392c 100644 --- a/spec/wibox/layout/overflow_spec.lua +++ b/spec/wibox/layout/overflow_spec.lua @@ -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