diff --git a/lib/wibox/layout/align.lua b/lib/wibox/layout/align.lua index 0d33ed64..af1ab51f 100644 --- a/lib/wibox/layout/align.lua +++ b/lib/wibox/layout/align.lua @@ -15,12 +15,13 @@ local widget_base = require("wibox.widget.base") local align = {} ---- Draw an align layout. +--- Calculate the layout of an align layout. -- @param context The context in which we are drawn. --- @param cr The cairo context to use. -- @param width The available width. -- @param height The available height. -function align:draw(context, cr, width, height) +function align:layout(context, width, height) + local result = {} + -- Draw will have to deal with all three align modes and should work in a -- way that makes sense if one or two of the widgets are missing (if they -- are all missing, it won't draw anything.) It should also handle the case @@ -45,8 +46,7 @@ function align:draw(context, cr, width, height) -- if all the space is taken, skip the rest, and draw just the middle -- widget if size_second >= size_remains then - base.draw_widget(context, cr, self.second, 0, 0, width, height) - return + return { widget_base.place_widget_at(self.second, 0, 0, width, height) } else -- the middle widget is sized first, the outside widgets are given -- the remaining space if available we will draw later @@ -84,7 +84,7 @@ function align:draw(context, cr, width, height) w = size_remains end end - base.draw_widget(context, cr, self.first, 0, 0, w, h) + table.insert(result, widget_base.place_widget_at(self.first, 0, 0, w, h)) end -- size_remains will be <= 0 if first used all the space if self.third and size_remains > 0 then @@ -110,7 +110,7 @@ function align:draw(context, cr, width, height) end end local x, y = width - w, height - h - base.draw_widget(context, cr, self.third, x, y, w, h) + table.insert(result, widget_base.place_widget_at(self.third, x, y, w, h)) end -- here we either draw the second widget in the space set aside for it -- in the beginning, or in the remaining space, if it is "inside" @@ -133,37 +133,27 @@ function align:draw(context, cr, width, height) x = floor( (width -w)/2 ) end end - base.draw_widget(context, cr, self.second, x, y, w, h) + table.insert(result, widget_base.place_widget_at(self.second, x, y, w, h)) end -end - -local function widget_changed(layout, old_w, new_w) - if old_w then - old_w:disconnect_signal("widget::updated", layout._emit_updated) - end - if new_w then - widget_base.check_widget(new_w) - new_w:weak_connect_signal("widget::updated", layout._emit_updated) - end - layout._emit_updated() + return result end --- Set the layout's first widget. This is the widget that is at the left/top function align:set_first(widget) - widget_changed(self, self.first, widget) self.first = widget + self:emit_signal("widget::layout_changed") end --- Set the layout's second widget. This is the centered one. function align:set_second(widget) - widget_changed(self, self.second, widget) self.second = widget + self:emit_signal("widget::layout_changed") end --- Set the layout's third widget. This is the widget that is at the right/bottom function align:set_third(widget) - widget_changed(self, self.third, widget) self.third = widget + self:emit_signal("widget::layout_changed") end --- Fit the align layout into the given space. The align layout will @@ -192,6 +182,7 @@ function align:fit(context, orig_width, orig_height) end return used_in_dir, used_in_other end + --- Set the expand mode which determines how sub widgets expand to take up -- unused space. Options are: -- "inside" - Default option. Size of outside widgets is determined using their @@ -210,22 +201,19 @@ function align:set_expand(mode) else self._expand = "inside" end - self:emit_signal("widget::updated") + self:emit_signal("widget::layout_changed") end function align:reset() for k, v in pairs({ "first", "second", "third" }) do self[v] = nil end - self:emit_signal("widget::updated") + self:emit_signal("widget::layout_changed") end local function get_layout(dir) local ret = widget_base.make_widget() ret.dir = dir - ret._emit_updated = function() - ret:emit_signal("widget::updated") - end for k, v in pairs(align) do if type(v) == "function" then diff --git a/spec/wibox/layout/align_spec.lua b/spec/wibox/layout/align_spec.lua index 4ea7772d..1c0434cd 100644 --- a/spec/wibox/layout/align_spec.lua +++ b/spec/wibox/layout/align_spec.lua @@ -5,11 +5,9 @@ local align = require("wibox.layout.align") local utils = require("wibox.test_utils") +local p = require("wibox.widget.base").place_widget_at -describe("wibox.layout.flex", function() - before_each(utils.stub_draw_widget) - after_each(utils.revert_draw_widget) - +describe("wibox.layout.align", function() describe("expand=none", function() local layout before_each(function() @@ -21,9 +19,8 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 10, 10 }, { 0, 0 }) end) - it("empty layout draw", function() - layout:draw(nil, nil, 0, 0) - utils.check_widgets_drawn({}) + it("empty layout layout", function() + assert.is.same({}, layout:layout(0, 0)) end) describe("with widgets", function() @@ -44,12 +41,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 100 }, { 15, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 100, 10 }, - { third, 0, 90, 100, 10 }, - { second, 0, 42, 100, 15 }, + it("layout", function() + assert.widget_layout(layout, { 100, 100 }, { + p(first, 0, 0, 100, 10), + p(third, 0, 90, 100, 10), + p(second, 0, 42, 100, 15), }) end) end) @@ -59,12 +55,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 5, 100 }, { 5, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 5, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 5, 10 }, - { third, 0, 90, 5, 10 }, - { second, 0, 42, 5, 15 }, + it("layout", function() + assert.widget_layout(layout, { 5, 100 }, { + p(first, 0, 0, 5, 10), + p(third, 0, 90, 5, 10), + p(second, 0, 42, 5, 15), }) end) end) @@ -74,12 +69,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 20 }, { 15, 20 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 20) - utils.check_widgets_drawn({ - { first, 0, 0, 100, 2 }, - { third, 0, 18, 100, 2 }, - { second, 0, 2, 100, 15 }, + it("layout", function() + assert.widget_layout(layout, { 100, 20 }, { + p(first, 0, 0, 100, 2), + p(third, 0, 18, 100, 2), + p(second, 0, 2, 100, 15), }) end) end) @@ -97,9 +91,8 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 10, 10 }, { 0, 0 }) end) - it("empty layout draw", function() - layout:draw(nil, nil, 0, 0) - utils.check_widgets_drawn({}) + it("empty layout layout", function() + assert.widget_layout(layout, { 0, 0 }, {}) end) describe("with widgets", function() @@ -120,12 +113,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 100 }, { 15, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 100, 42 }, - { third, 0, 58, 100, 42 }, - { second, 0, 42, 100, 15 }, + it("layout", function() + assert.widget_layout(layout, { 100, 100 }, { + p(first, 0, 0, 100, 42), + p(third, 0, 58, 100, 42), + p(second, 0, 42, 100, 15), }) end) end) @@ -135,12 +127,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 5, 100 }, { 5, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 5, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 5, 42 }, - { third, 0, 58, 5, 42 }, - { second, 0, 42, 5, 15 }, + it("layout", function() + assert.widget_layout(layout, { 5, 100 }, { + p(first, 0, 0, 5, 42), + p(third, 0, 58, 5, 42), + p(second, 0, 42, 5, 15), }) end) end) @@ -150,12 +141,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 20 }, { 15, 20 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 20) - utils.check_widgets_drawn({ - { first, 0, 0, 100, 2 }, - { third, 0, 18, 100, 2 }, - { second, 0, 2, 100, 15 }, + it("layout", function() + assert.widget_layout(layout, { 100, 20 }, { + p(first, 0, 0, 100, 2), + p(third, 0, 18, 100, 2), + p(second, 0, 2, 100, 15), }) end) end) @@ -173,9 +163,8 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 10, 10 }, { 0, 0 }) end) - it("empty layout draw", function() - layout:draw(nil, nil, 0, 0) - utils.check_widgets_drawn({}) + it("empty layout layout", function() + assert.widget_layout(layout, { 0, 0 }, {}) end) describe("with widgets", function() @@ -196,12 +185,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 100 }, { 15, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 100, 10 }, - { third, 0, 90, 100, 10 }, - { second, 0, 10, 100, 80 }, + it("layout", function() + assert.widget_layout(layout, { 100, 100 }, { + p(first, 0, 0, 100, 10), + p(third, 0, 90, 100, 10), + p(second, 0, 10, 100, 80), }) end) end) @@ -211,12 +199,11 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 5, 100 }, { 5, 35 }) end) - it("draw", function() - layout:draw("wibox", "cr", 5, 100) - utils.check_widgets_drawn({ - { first, 0, 0, 5, 10 }, - { third, 0, 90, 5, 10 }, - { second, 0, 10, 5, 80 }, + it("layout", function() + assert.widget_layout(layout, { 5, 100 }, { + p(first, 0, 0, 5, 10), + p(third, 0, 90, 5, 10), + p(second, 0, 10, 5, 80), }) end) end) @@ -226,12 +213,10 @@ describe("wibox.layout.flex", function() assert.widget_fit(layout, { 100, 20 }, { 15, 20 }) end) - it("draw", function() - layout:draw("wibox", "cr", 100, 20) - --- XXX: Shouldn't this also draw part of the second widget? - utils.check_widgets_drawn({ - { first, 0, 0, 100, 10 }, - { third, 0, 10, 100, 10 }, + it("layout", function() + assert.widget_layout(layout, { 100, 20 }, { + p(first, 0, 0, 100, 10), + p(third, 0, 10, 100, 10), }) end) end) diff --git a/spec/wibox/test_utils.lua b/spec/wibox/test_utils.lua index f6f859a9..dc39761d 100644 --- a/spec/wibox/test_utils.lua +++ b/spec/wibox/test_utils.lua @@ -5,6 +5,7 @@ local object = require("gears.object") local cache = require("gears.cache") +local matrix_equals = require("gears.matrix").equals local wbase = require("wibox.widget.base") local lbase = require("wibox.layout.base") local say = require("say") @@ -12,7 +13,7 @@ local assert = require("luassert") local spy = require("luassert.spy") local stub = require("luassert.stub") -local real_draw_widget = lbase.draw_widget +local real_draw_widget = wbase.draw_widget local widgets_drawn = nil -- This function would reject stubbed widgets @@ -29,7 +30,7 @@ end -- {{{ Own widget-based assertions local function widget_fit(state, arguments) if #arguments ~= 3 then - return false + error("Have " .. #arguments .. " arguments, but need 3") end local widget = arguments[1] @@ -52,6 +53,47 @@ local function widget_fit(state, arguments) end say:set("assertion.widget_fit.positive", "Offering (%s, %s) to widget and expected (%s, %s), but got (%s, %s)") assert:register("assertion", "widget_fit", widget_fit, "assertion.widget_fit.positive", "assertion.widget_fit.positive") + +local function widget_layout(state, arguments) + if #arguments ~= 3 then + error("Have " .. #arguments .. " arguments, but need 3") + end + + local widget = arguments[1] + local given = arguments[2] + local expected = arguments[3] + local children = widget.layout and widget:layout({ "fake context" }, given[1], given[2]) or {} + + local fits = true + if #children ~= #expected then + fits = false + else + for i = 1, #children do + local child, expected = children[i], expected[i] + if child._widget ~= expected._widget or + child._width ~= expected._width or + child._height ~= expected._height or + not matrix_equals(child._matrix, expected._matrix) then + fits = false + break + end + end + end + + if state.mod == fits then + return true + end + + -- For proper error message, mess with the arguments + arguments[1] = expected + arguments[2] = children + arguments[3] = given[1] + arguments[4] = given[2] + + return false +end +say:set("assertion.widget_layout.positive", "Expected:\n%s\nbut got:\n%s\nwhen offering (%s, %s) to widget") +assert:register("assertion", "widget_layout", widget_layout, "assertion.widget_layout.positive", "assertion.widget_layout.positive") -- }}} return {