From 3b1a80a9ce468de34b40d0951ca3e34196a7f886 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Wed, 29 Jun 2022 17:11:01 +0200 Subject: [PATCH] feat(w.c.conditional): Implement conditional container This container allows showing or hiding a child widget based on a boolean state property. --- lib/wibox/container/conditional.lua | 109 ++++++++++++++++++ lib/wibox/container/init.lua | 1 + spec/wibox/container/conditional_spec.lua | 48 ++++++++ .../container/conditional/comparison.lua | 62 ++++++++++ 4 files changed, 220 insertions(+) create mode 100644 lib/wibox/container/conditional.lua create mode 100644 spec/wibox/container/conditional_spec.lua create mode 100644 tests/examples/wibox/container/conditional/comparison.lua diff --git a/lib/wibox/container/conditional.lua b/lib/wibox/container/conditional.lua new file mode 100644 index 000000000..28bec61b9 --- /dev/null +++ b/lib/wibox/container/conditional.lua @@ -0,0 +1,109 @@ +--------------------------------------------------------------------------- +-- A simple container that will hide its child widget based a +-- boolean state variable. +-- +--@DOC_wibox_container_conditional_comparison_EXAMPLE@ +-- +-- @author Lucas Schwiderski +-- @copyright 2022 Lucas Schwiderski +-- @containermod wibox.container.conditional +-- @supermodule wibox.widget.base +--------------------------------------------------------------------------- + +local base = require("wibox.widget.base") +local gtable = require("gears.table") +local gobject = require("gears.object") + +local conditional = { mt = {} } + + +function conditional:fit(context, width, height) + if not self._private.state then + return 0, 0 + end + + return base.fit_widget(self, context, self._private.widget, width, height) +end + + +function conditional:layout(_, width, height) + if not self._private.state then + return {} + end + + return { base.place_widget_at(self._private.widget, 0, 0, width, height) } +end + + +--- The conditional state. +-- +-- The child widget is shown or hidden based on this state. +-- +-- @property state +-- @tparam boolean state +-- @propemits true false + +function conditional:set_state(state) + state = not (not state) + + if self._private.state == state then + return + end + + self._private.state = state + + self:emit_signal("widget::layout_changed") + self:emit_signal("property::state", state) +end + +function conditional:get_state() + return self._private.state +end + + +--- The widget to be displayed based on the state. +-- @property widget +-- @tparam widget widget +-- @propemits true false +-- @interface container + +conditional.set_widget = base.set_widget_common +function conditional:get_widget() + return self._private.widget +end + + +function conditional:set_children(widgets) + self:set_widget(widgets[1]) +end + +function conditional:get_children() + return { self._private.widget } +end + + +local function new(widget, state) + local ret = base.make_widget(nil, nil, { enable_properties = true}) + + gtable.crush(ret, conditional, true) + ret.widget_name = gobject.modulename(2) + + ret._private.widget = widget + + if type(state) == "boolean" then + ret._private.state = state + else + ret._private.state = true + end + + return ret +end + + +function conditional.mt:__call(...) + return new(...) +end + +return setmetatable(conditional, conditional.mt) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/lib/wibox/container/init.lua b/lib/wibox/container/init.lua index 69926fb2f..f917c2a3f 100644 --- a/lib/wibox/container/init.lua +++ b/lib/wibox/container/init.lua @@ -18,6 +18,7 @@ return setmetatable({ arcchart = require("wibox.container.arcchart"); place = require("wibox.container.place"); tile = require("wibox.container.tile"); + conditional = require("wibox.container.conditional"); }, {__call = function(_, args) return base.make_widget_declarative(args) end}) -- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/spec/wibox/container/conditional_spec.lua b/spec/wibox/container/conditional_spec.lua new file mode 100644 index 000000000..7fad698b5 --- /dev/null +++ b/spec/wibox/container/conditional_spec.lua @@ -0,0 +1,48 @@ +--------------------------------------------------------------------------- +-- @author Lucas Schwiderski +-- @copyright 2022 Lucas Schwiderski +--------------------------------------------------------------------------- + +local conditional = require("wibox.container.conditional") +local utils = require("wibox.test_utils") +local base = require("wibox.widget.base") +local p = require("wibox.widget.base").place_widget_at + +describe("wibox.container.conditional", function() + it("implements the common API", function() + utils.test_container(conditional()) + end) + + describe("constructor", function() + it("applies arguments", function() + local inner = base.empty_widget() + local state = false + local widget = conditional(inner, state) + + assert.is.equal(inner, widget.widget) + assert.is.equal(state, widget.state) + end) + + it("defaults to state == true", function() + local widget = conditional() + assert.is_true(widget.state) + end) + end) + + it("hides the child widget when state == false", function() + local inner = utils.widget_stub(10, 10) + local widget = conditional(inner) + + assert.widget_fit(widget, { 10, 10 }, { 10, 10 }) + assert.widget_layout(widget, { 10, 10 }, { + p(inner, 0, 0, 10, 10), + }) + + widget.state = false + + assert.widget_fit(widget, { 10, 10 }, { 0, 0 }) + assert.widget_layout(widget, { 0, 0 }, {}) + end) +end) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 diff --git a/tests/examples/wibox/container/conditional/comparison.lua b/tests/examples/wibox/container/conditional/comparison.lua new file mode 100644 index 000000000..dc71283ad --- /dev/null +++ b/tests/examples/wibox/container/conditional/comparison.lua @@ -0,0 +1,62 @@ +--DOC_HIDE_START --DOC_GEN_IMAGE +local parent = ... +local wibox = require("wibox") +local beautiful = require("beautiful") + +parent.spacing = 10 + +parent:add(wibox.widget { + layout = wibox.layout.fixed.vertical, + spacing = 2, + { + markup = "state == true", + widget = wibox.widget.textbox + }, +--DOC_HIDE_END +{ + { + { + text = "Hello, World!", + widget = wibox.widget.textbox, + }, + state = true, + widget = wibox.container.conditional, + }, + bg = beautiful.bg_normal, + widget = wibox.container.background, +}, +--DOC_HIDE_START +}) + +parent:add(wibox.widget { + layout = wibox.layout.fixed.vertical, + spacing = 2, + { + markup = "state == false", + widget = wibox.widget.textbox + }, +--DOC_HIDE_END +{ + { --DOC_HIDE + { + { + text = "Hello, World!", + widget = wibox.widget.textbox, + }, + state = false, + widget = wibox.container.conditional, + }, +--DOC_HIDE_START + strategy = "min", + width = 100, + height = 18, + widget = wibox.container.constraint, + }, +--DOC_HIDE_END + bg = beautiful.bg_normal, + widget = wibox.container.background, +}, +--DOC_HIDE_START +}) + +-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80