awesome/lib/wibox/widget/template.lua

207 lines
6.5 KiB
Lua
Raw Normal View History

2021-08-28 14:30:22 +02:00
---------------------------------------------------------------------------
-- An abstract widget that handles a preset of concrete widget.
--
-- The `wibox.widget.template` widget is an abstraction layer that contains a
-- concrete widget definition. The template widget can be used to build widgets
-- that the user can customize at their will, thanks to the template mechanism.
--
2021-11-12 16:02:24 +01:00
-- Common usage examples
-- =====================
--
-- A basic implementation of the template widget needs a widget definition and
-- a callback to manage widget updates.
--
-- The `:update()` can be called later to update the widget template. Arguments
-- can be provided to the `:update()` method, it will be forwarded to the
-- `update_callback` function.
--
--@DOC_wibox_widget_template_basic_textbox_EXAMPLE@
--
-- Alternatively, you can declare the `template` widget instance using the
-- declarative pattern (both variants are strictly equivalent):
--
--@DOC_wibox_widget_template_basic_textbox_declarative_EXAMPLE@
--
2021-08-28 14:30:22 +02:00
-- @author Aire-One
-- @copyright 2021 Aire-One <aireone@aireone.xyz>
--
2021-11-12 16:02:24 +01:00
-- @widgetmod wibox.widget.template
2021-08-28 14:30:22 +02:00
-- @supermodule wibox.widget.base
---------------------------------------------------------------------------
local wbase = require("wibox.widget.base")
local gtable = require("gears.table")
local gtimer = require("gears.timer")
local template = {
mt = {},
queued_updates = {},
2021-08-28 14:30:22 +02:00
}
2021-11-12 16:03:52 +01:00
-- Layout this layout.
-- @method layout
-- @hidden
function template:layout(_, width, height)
if not self._private.widget then
return
end
return { wbase.place_widget_at(self._private.widget, 0, 0, width, height) }
end
-- Fit this layout into the given area.
2021-11-12 16:03:52 +01:00
-- @method fit
-- @hidden
function template:fit(context, width, height)
if not self._private.widget then
return 0, 0
end
return wbase.fit_widget(self, context, self._private.widget, width, height)
end
2021-11-12 16:03:52 +01:00
-- Draw the widget if it's actually a widget instance
-- @method draw
-- @hidden
function template:draw(...)
if type(self._private.widget.draw) == "function" then
return self._private.widget:draw(...)
end
end
2021-11-12 16:03:52 +01:00
-- Call the update widget method now and clean the queue for this widget
-- instance.
-- @method _do_update_now
-- @hidden
function template:_do_update_now()
if type(self._private.update_callback) == "function" then
self._private.update_callback(self, self._private.update_args)
end
self._private.update_args = nil
template.queued_updates[self] = nil
2021-08-28 14:30:22 +02:00
end
--- Update the widget.
-- This function will call the `update_callback` function at the end of the
-- current GLib event loop. Updates are batched by event loop, it means that the
-- widget can only be update once by event loop. If the `template:update` method
-- is called multiple times during the same GLib event loop, only the first call
-- will be run.
-- All arguments are passed to the queued `update_callback` call.
2021-11-12 16:03:52 +01:00
-- @tparam[opt] table args A table to pass to the widget update function.
-- @method update
2021-08-28 14:30:22 +02:00
function template:update(args)
if type(args) == "table" then
2021-10-23 16:05:49 +02:00
self._private.update_args = gtable.crush(
gtable.clone(self._private.update_args or {}, false),
args
)
end
2021-08-28 14:30:22 +02:00
if not template.queued_updates[self] then
2021-10-23 16:05:49 +02:00
gtimer.delayed_call(function()
self:_do_update_now()
end)
2021-08-28 14:30:22 +02:00
template.queued_updates[self] = true
end
end
2021-11-12 16:03:52 +01:00
--- Change the widget template.
-- @tparam table|widget|function widget_template The new widget to use as a
-- template.
-- @method set_template
-- @emits widget::redraw_needed
-- @hidden
function template:set_template(widget_template)
local widget = type(widget_template) == "function" and widget_template()
or widget_template
or wbase.empty_widget()
self._private.template = widget
self._private.widget = wbase.make_widget_from_value(widget)
-- We need to connect to these signals to actually redraw the template
-- widget when its child needs to.
local signals = {
"widget::redraw_needed",
"widget::layout_changed",
}
for _, signal in pairs(signals) do
self._private.widget:connect_signal(signal, function(...)
self:emit_signal(signal, ...)
end)
end
self:emit_signal("widget::redraw_needed")
end
2021-11-12 16:03:52 +01:00
--- Give the internal widget instance.
-- @treturn widget The widget instance.
-- @method get_widget
-- @hidden
function template:get_widget()
return self._private.widget
end
2021-11-12 16:03:52 +01:00
--- Set the update_callback property.
-- @tparam function update_callback The new callback function.
-- @method set_update_callback
-- @hidden
function template:set_update_callback(update_callback)
assert(type(update_callback) == "function" or update_callback == nil)
self._private.update_callback = update_callback
end
2021-11-12 16:03:52 +01:00
--- Hack to allow automatic update of the widget at construction time.
-- This is supposed to be a setter for an `update_now` property. This property
-- however doesn't exist. We use this setter in the scope of the widget
-- construction from wibox.widget internals to offer an easy way for the user to
-- ask for the widget to be update right after its construction.
-- Note : The update is not instantly called, but is registered as a normal
-- update from the `:update()` method.
-- @tparam[opt] boolean update_now Update the widget now.
-- @method set_update_now
-- @hidden
function template:set_update_now(update_now)
if update_now then
self:update()
end
end
2021-08-28 14:30:22 +02:00
--- Create a new `wibox.widget.template` instance.
-- @tparam[opt] table args
2021-10-23 16:04:27 +02:00
-- @tparam[opt] table|widget|function args.template The widget template to use.
2021-11-12 16:03:52 +01:00
-- @tparam[opt] function args.update_callback The callback function to update
-- the widget.
-- @tparam[opt] boolean args.update_now Update the widget after its
-- construction. This will call the `:update()` method with no parameter.
2021-08-28 14:30:22 +02:00
-- @treturn wibox.widget.template The new instance.
2021-11-12 16:03:52 +01:00
-- @constructorfct wibox.widget.template
2021-08-28 14:30:22 +02:00
function template.new(args)
args = args or {}
local ret = wbase.make_widget(nil, nil, { enable_properties = true })
2021-08-28 14:30:22 +02:00
gtable.crush(ret, template, true)
2021-08-28 14:30:22 +02:00
ret:set_template(args.template)
ret:set_update_callback(args.update_callback)
ret:set_update_now(args.update_now)
2021-08-28 14:30:22 +02:00
if args.buttons then
ret:set_buttons(args.buttons)
end
return ret
2021-08-28 14:30:22 +02:00
end
function template.mt:__call(...)
2021-08-28 14:30:22 +02:00
return template.new(...)
end
return setmetatable(template, template.mt)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80