From f31afd8cb79ec4a0f361e5b37c5dfe8d7e735bfc Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee Date: Sun, 13 Aug 2017 02:50:19 -0400 Subject: [PATCH] naughty: Add an icon widget. This tracks the notification icon and add some resize strategies. --- lib/naughty/widget/icon.lua | 158 ++++++++++++++++++++++++++++++++++++ lib/naughty/widget/init.lua | 1 + 2 files changed, 159 insertions(+) create mode 100644 lib/naughty/widget/icon.lua diff --git a/lib/naughty/widget/icon.lua b/lib/naughty/widget/icon.lua new file mode 100644 index 000000000..cac135645 --- /dev/null +++ b/lib/naughty/widget/icon.lua @@ -0,0 +1,158 @@ +---------------------------------------------------------------------------- +--- A notification square icon. +-- +-- 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 +-- @see wibox.widget.imagebox +---------------------------------------------------------------------------- +local imagebox = require("wibox.widget.imagebox") +local gtable = require("gears.table") +local beautiful = require("beautiful") +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) / 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 + +function icon:set_notification(notif) + if self._private.notification == notif then return end + + if self._private.notification then + self._private.notification:disconnect_signal("destroyed", + self._private.icon_changed_callback) + end + + self:set_image(notif.icon) + + self._private.notification = notif + + notif:connect_signal("poperty::icon", self._private.icon_changed_callback) +end + +local valid_strategies = { + scale = true, + center = true, + resize = true, +} + +--- How small icons are handled. +-- +-- Valid values are: +-- +-- * **scale**: Scale the icon up to the optimal size. +-- * **center**: Keep the icon size and draw it in the center +-- * **resize**: Change the size of the widget itself (*default*). +-- +-- Note that the size upper bound is defined by +-- `beautiful.notification_icon_size`. +-- +--@DOC_wibox_nwidget_icon_strategy_EXAMPLE@ +-- +-- @property resize_strategy +-- @param string + +function icon:set_resize_strategy(strategy) + assert(valid_strategies[strategy], "Invalid strategy") + + self._private.resize_strategy = strategy + + self:emit_signal("widget::redraw_needed") +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) + + function tb._private.icon_changed_callback() + tb:set_image(tb._private.notification.icon) + end + + if args.notification then + tb:set_notification(args.notification) + end + + return tb +end + +--@DOC_widget_COMMON@ + +--@DOC_object_COMMON@ + +return setmetatable(icon, {__call = function(_, ...) return new(...) end}) diff --git a/lib/naughty/widget/init.lua b/lib/naughty/widget/init.lua index ff74b5387..ff7c632bd 100644 --- a/lib/naughty/widget/init.lua +++ b/lib/naughty/widget/init.lua @@ -6,4 +6,5 @@ return { title = require( "naughty.widget.title" ); + icon = require( "naughty.widget.icon" ); }