common: Refactor awful.widget.common to support external extensions

This commit allow user defined delegates to be used as list elements.
This put an end to the endless attempt to cram more features into this
code.

A widget template (non-instantiated) is passed to the arguments and
is created by the common code. It also supports "roles" where some
user defined widgets can replace the old textbox or imagebox.
This commit is contained in:
Emmanuel Lepage Vallee 2017-08-10 00:28:06 -04:00
parent 2e7cd2b2ef
commit f147f0d28a
1 changed files with 94 additions and 50 deletions

View File

@ -9,7 +9,9 @@ local type = type
local ipairs = ipairs local ipairs = ipairs
local capi = { button = button } local capi = { button = button }
local wibox = require("wibox") local wibox = require("wibox")
local gdebug = require("gears.debug")
local dpi = require("beautiful").xresources.apply_dpi local dpi = require("beautiful").xresources.apply_dpi
local base = require("wibox.widget.base")
--- Common utilities for awful widgets --- Common utilities for awful widgets
local common = {} local common = {}
@ -36,6 +38,52 @@ function common.create_buttons(buttons, object)
end end
end end
local function default_template()
local ib = wibox.widget.imagebox()
local tb = wibox.widget.textbox()
local bgb = wibox.container.background()
local tbm = wibox.container.margin(tb, dpi(4), dpi(4))
local ibm = wibox.container.margin(ib, dpi(4))
local l = wibox.layout.fixed.horizontal()
-- All of this is added in a fixed widget
l:fill_space(true)
l:add(ibm)
l:add(tbm)
-- And all of this gets a background
bgb:set_widget(l)
return {
ib = ib,
tb = tb,
bgb = bgb,
tbm = tbm,
ibm = ibm,
primary = l,
}
end
local function custom_template(args)
local l = base.make_widget_from_value(args.widget_template)
-- The template system requires being able to get children elements by ids.
-- This is not optimal, but for now there is no way around it.
assert(l.get_children_by_id,"The given widget template did not result in a"..
"layout with a 'get_children_by_id' method")
return {
ib = l:get_children_by_id( "icon_role" )[1],
tb = l:get_children_by_id( "text_role" )[1],
bgb = l:get_children_by_id( "background_role" )[1],
tbm = l:get_children_by_id( "text_margin_role" )[1],
ibm = l:get_children_by_id( "icon_margin_role" )[1],
primary = l,
update_callback = l.update_callback,
create_callback = l.create_callback,
}
end
--- Common update method. --- Common update method.
-- @param w The widget. -- @param w The widget.
-- @tab buttons -- @tab buttons
@ -44,73 +92,69 @@ end
-- has to return `text`, `bg`, `bg_image`, `icon`. -- has to return `text`, `bg`, `bg_image`, `icon`.
-- @tab data Current data/cache, indexed by objects. -- @tab data Current data/cache, indexed by objects.
-- @tab objects Objects to be displayed / updated. -- @tab objects Objects to be displayed / updated.
function common.list_update(w, buttons, label, data, objects) -- @tparam[opt={}] table args
function common.list_update(w, buttons, label, data, objects, args)
-- update the widgets, creating them if needed -- update the widgets, creating them if needed
w:reset() w:reset()
for i, o in ipairs(objects) do for i, o in ipairs(objects) do
local cache = data[o] local cache = data[o]
local ib, tb, bgb, tbm, ibm, l
if cache then
ib = cache.ib
tb = cache.tb
bgb = cache.bgb
tbm = cache.tbm
ibm = cache.ibm
else
ib = wibox.widget.imagebox()
tb = wibox.widget.textbox()
bgb = wibox.container.background()
tbm = wibox.container.margin(tb, dpi(4), dpi(4))
ibm = wibox.container.margin(ib, dpi(4))
l = wibox.layout.fixed.horizontal()
-- All of this is added in a fixed widget if not cache then
l:fill_space(true) cache = (args and args.widget_template) and
l:add(ibm) custom_template(args) or default_template()
l:add(tbm)
-- And all of this gets a background cache.primary:buttons(common.create_buttons(buttons, o))
bgb:set_widget(l)
bgb:buttons(common.create_buttons(buttons, o)) if cache.create_callback then
cache.create_callback(cache.primary, o, i, objects)
end
data[o] = { data[o] = cache
ib = ib, elseif cache.update_callback then
tb = tb, cache.update_callback(cache.primary, o, i, objects)
bgb = bgb,
tbm = tbm,
ibm = ibm,
}
end end
local text, bg, bg_image, icon, args = label(o, tb) local text, bg, bg_image, icon, item_args = label(o, cache.tb)
args = args or {} item_args = item_args or {}
-- The text might be invalid, so use pcall. -- The text might be invalid, so use pcall.
if text == nil or text == "" then if cache.tbm and (text == nil or text == "") then
tbm:set_margins(0) cache.tbm:set_margins(0)
else elseif cache.tb then
if not tb:set_markup_silently(text) then if not cache.tb:set_markup_silently(text) then
tb:set_markup("<i>&lt;Invalid text&gt;</i>") cache.tb:set_markup("<i>&lt;Invalid text&gt;</i>")
end end
end end
bgb:set_bg(bg)
if type(bg_image) == "function" then if cache.bgb then
-- TODO: Why does this pass nil as an argument? cache.bgb:set_bg(bg)
bg_image = bg_image(tb,o,nil,objects,i)
end --TODO v5 remove this if, it existed only for a removed and
bgb:set_bgimage(bg_image) -- undocumented API
if icon then if type(bg_image) ~= "function" then
ib:set_image(icon) cache.bgb:set_bgimage(bg_image)
else else
ibm:set_margins(0) gdebug.deprecate("If you read this, you used an undocumented API"..
" which has been replaced by the new awful.widget.common "..
"templating system, please migrate now. This feature is "..
"already staged for removal", {
deprecated_in = 4
})
end
cache.bgb.shape = item_args.shape
cache.bgb.shape_border_width = item_args.shape_border_width
cache.bgb.shape_border_color = item_args.shape_border_color
end end
bgb.shape = args.shape if cache.ib and icon then
bgb.shape_border_width = args.shape_border_width cache.ib:set_image(icon)
bgb.shape_border_color = args.shape_border_color elseif cache.ibm then
cache.ibm:set_margins(0)
end
w:add(bgb) w:add(cache.primary)
end end
end end