awesome/lib/naughty/widget/icon.lua

187 lines
5.4 KiB
Lua

----------------------------------------------------------------------------
--- A notification square icon widget.
--
-- This widget is a specialized `wibox.widget.imagebox` with the following extra
-- features:
--
-- * Honor the `beautiful` notification variables.
-- * Restrict the size avoid huge notifications
-- * Provides some strategies to handle small icons
-- * React to the `naughty.notification` object icon changes.
--
--@DOC_wibox_nwidget_icon_simple_EXAMPLE@
--
-- @author Emmanuel Lepage Vallee <elv1313@gmail.com>
-- @copyright 2017 Emmanuel Lepage Vallee
-- @widgetmod naughty.widget.icon
-- @supermodule wibox.widget.imagebox
-- @see wibox.widget.imagebox
----------------------------------------------------------------------------
local imagebox = require("wibox.widget.imagebox")
local gtable = require("gears.table")
local beautiful = require("beautiful")
local gsurface = require("gears.surface")
local dpi = require("beautiful.xresources").apply_dpi
local icon = {}
--- The default way to resize the icon.
-- @beautiful beautiful.notification_icon_resize_strategy
-- @param number
function icon:fit(_, width, height)
-- Until someone complains, adding a "leave blank space" isn't supported
if not self._private.image then return 0, 0 end
local maximum = math.min(width, height)
local strategy = self._private.resize_strategy or "resize"
local optimal = math.min(beautiful.notification_icon_size or dpi(48), maximum)
local w = self._private.image:get_width()
local h = self._private.image:get_height()
if strategy == "resize" then
return math.min(w, optimal, maximum), math.min(h, optimal, maximum)
else
return optimal, optimal
end
end
function icon:draw(_, cr, width, height)
if not self._private.image then return end
if width == 0 or height == 0 then return end
-- Let's scale the image so that it fits into (width, height)
local strategy = self._private.resize_strategy or "resize"
local w = self._private.image:get_width()
local h = self._private.image:get_height()
local aspect = width / w
local aspect_h = height / h
if aspect > aspect_h then aspect = aspect_h end
if aspect < 1 or (strategy == "scale" and (w < width or h < height)) then
cr:scale(aspect, aspect)
end
local x, y = 0, 0
if (strategy == "center" and aspect < 1) or strategy == "resize" then
x = math.floor((width - w*aspect) / 2)
y = math.floor((height - h*aspect) / 2)
elseif strategy == "center" and aspect > 1 then
x = math.floor((width - w) / 2)
y = math.floor((height - h) / 2)
end
cr:set_source_surface(self._private.image, x, y)
cr:paint()
end
--- The attached notification.
-- @property notification
-- @tparam naughty.notification notification
-- @propertydefault This is usually set in the construtor.
-- @propemits true false
function icon:set_notification(notif)
local old = (self._private.notification or {})[1]
if old == notif then return end
if old then
old:disconnect_signal("destroyed",
self._private.icon_changed_callback)
end
local icn = gsurface.load_silently(notif.icon)
if icn then
self:set_image(icn)
end
self._private.notification = setmetatable({notif}, {__mode="v"})
notif:connect_signal("property::icon", self._private.icon_changed_callback)
self:emit_signal("property::notification", notif)
end
local valid_strategies = {
scale = true,
center = true,
resize = true,
}
--- How small icons are handled.
--
-- Note that the size upper bound is defined by
-- `beautiful.notification_icon_size`.
--
--@DOC_wibox_nwidget_icon_strategy_EXAMPLE@
--
-- @property resize_strategy
-- @tparam string resize_strategy
-- @propemits true false
-- @propertyvalue "scale" Scale the icon up to the optimal size.
-- @propertyvalue "center" Keep the icon size and draw it in the center
-- @propertyvalue "resize" Change the size of the widget itself (*default*).
-- @usebeautiful beautiful.notification_icon_resize_strategy The fallback when
-- there is no specified strategy.
-- @usebeautiful beautiful.notification_icon_size The size upper bound.
--- The default notification icon size.
-- @beautiful beautiful.notification_icon_size
-- @tparam number notification_icon_size The size (in pixels).
function icon:set_resize_strategy(strategy)
assert(valid_strategies[strategy], "Invalid strategy")
self._private.resize_strategy = strategy
self:emit_signal("widget::redraw_needed")
self:emit_signal("property::resize_strategy", strategy)
end
function icon:get_resize_strategy()
return self._private.resize_strategy
or beautiful.notification_icon_resize_strategy
or "resize"
end
--- Create a new naughty.widget.icon.
-- @tparam table args
-- @tparam naughty.notification args.notification The notification.
-- @constructorfct naughty.widget.icon
local function new(args)
args = args or {}
local tb = imagebox()
gtable.crush(tb, icon, true)
tb._private.notification = {}
function tb._private.icon_changed_callback()
local n = tb._private.notification[1]
if not n then return end
local icn = gsurface.load_silently(n.icon)
if icn then
tb:set_image(icn)
end
end
if args.notification then
tb:set_notification(args.notification)
end
return tb
end
--@DOC_object_COMMON@
return setmetatable(icon, {__call = function(_, ...) return new(...) end})