diff options
Diffstat (limited to 'awesome/lib/awful/tooltip.lua')
-rw-r--r-- | awesome/lib/awful/tooltip.lua | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/awesome/lib/awful/tooltip.lua b/awesome/lib/awful/tooltip.lua deleted file mode 100644 index cd151c4..0000000 --- a/awesome/lib/awful/tooltip.lua +++ /dev/null @@ -1,616 +0,0 @@ -------------------------------------------------------------------------- ---- Tooltip module for awesome objects. --- --- A tooltip is a small hint displayed when the mouse cursor --- hovers a specific item. --- In awesome, a tooltip can be linked with almost any --- object having a `:connect_signal()` method and receiving --- `mouse::enter` and `mouse::leave` signals. --- --- How to create a tooltip? --- --- --- --- myclock = wibox.widget.textclock({}, "%T", 1) --- myclock_t = awful.tooltip({ --- objects = { myclock }, --- timer_function = function() --- return os.date("Today is %A %B %d %Y\nThe time is %T") --- end, --- }) --- --- How to add the same tooltip to multiple objects? --- --- --- --- myclock_t:add_to_object(obj1) --- myclock_t:add_to_object(obj2) --- --- Now the same tooltip is attached to `myclock`, `obj1`, `obj2`. --- --- How to remove a tooltip from several objects? --- --- --- --- myclock_t:remove_from_object(obj1) --- myclock_t:remove_from_object(obj2) --- --- Now the same tooltip is only attached to `myclock`. --- --- @author Sébastien Gross <seb•ɱɩɲʋʃ•awesome•ɑƬ•chezwam•ɖɵʈ•org> --- @copyright 2009 Sébastien Gross --- @classmod awful.tooltip -------------------------------------------------------------------------- - -local mouse = mouse -local timer = require("gears.timer") -local util = require("awful.util") -local object = require("gears.object") -local color = require("gears.color") -local wibox = require("wibox") -local a_placement = require("awful.placement") -local abutton = require("awful.button") -local shape = require("gears.shape") -local beautiful = require("beautiful") -local textbox = require("wibox.widget.textbox") -local dpi = require("beautiful").xresources.apply_dpi -local cairo = require("lgi").cairo -local setmetatable = setmetatable -local unpack = unpack or table.unpack -- luacheck: globals unpack (compatibility with Lua 5.1) -local ipairs = ipairs -local capi = {mouse=mouse, awesome=awesome} - -local tooltip = { mt = {} } - --- The mouse point is 1x1, so anything aligned based on it as parent --- geometry will go out of bound. To get the desired placement, it is --- necessary to swap left with right and top with bottom -local align_convert = { - top_left = "bottom_right", - left = "right", - bottom_left = "top_right", - right = "left", - top_right = "bottom_left", - bottom_right = "top_left", - top = "bottom", - bottom = "top", -} - --- If the wibox is under the cursor, it will trigger a mouse::leave -local offset = { - top_left = {x = 0, y = 0 }, - left = {x = 0, y = 0 }, - bottom_left = {x = 0, y = 0 }, - right = {x = 1, y = 0 }, - top_right = {x = 0, y = 0 }, - bottom_right = {x = 1, y = 1 }, - top = {x = 0, y = 0 }, - bottom = {x = 0, y = 1 }, -} - ---- The tooltip border color. --- @beautiful beautiful.tooltip_border_color - ---- The tooltip background color. --- @beautiful beautiful.tooltip_bg - ---- The tooltip foregound (text) color. --- @beautiful beautiful.tooltip_fg - ---- The tooltip font. --- @beautiful beautiful.tooltip_font - ---- The tooltip border width. --- @beautiful beautiful.tooltip_border_width - ---- The tooltip opacity. --- @beautiful beautiful.tooltip_opacity - ---- The default tooltip shape. --- By default, all tooltips are rectangles, however, by setting this variables, --- they can default to rounded rectangle or stretched octogons. --- @beautiful beautiful.tooltip_shape --- @tparam[opt=gears.shape.rectangle] function shape A `gears.shape` compatible function --- @see shape --- @see gears.shape - -local function apply_shape(self) - local s = self._private.shape - - local wb = self.wibox - - if not s then - -- Clear the shape - if wb.shape_bounding then - wb.shape_bounding = nil - wb:set_bgimage(nil) - end - - return - end - - local w, h = wb.width, wb.height - - -- First, create a A1 mask for the shape bounding itself - local img = cairo.ImageSurface(cairo.Format.A1, w, h) - local cr = cairo.Context(img) - - cr:set_source_rgba(1,1,1,1) - - s(cr, w, h, unpack(self._private.shape_args or {})) - cr:fill() - wb.shape_bounding = img._native - - -- The wibox background uses ARGB32 border so tooltip anti-aliasing works - -- when an external compositor is used. This will look better than - -- the capi.drawin's own border support. - img = cairo.ImageSurface(cairo.Format.ARGB32, w, h) - cr = cairo.Context(img) - - -- Draw the border (multiply by 2, then mask the inner part to save a path) - local bw = (self._private.border_width - or beautiful.tooltip_border_width - or beautiful.border_width or 0) * 2 - - -- Fix anti-aliasing - if bw > 2 and awesome.composite_manager_running then - bw = bw - 1 - end - - local bc = self._private.border_color - or beautiful.tooltip_border_color - or beautiful.border_normal - or "#ffcb60" - - cr:translate(bw, bw) - s(cr, w-2*bw, h-2*bw, unpack(self._private.shape_args or {})) - cr:set_line_width(bw) - cr:set_source(color(bc)) - cr:stroke_preserve() - cr:clip() - - local bg = self._private.bg - or beautiful.tooltip_bg - or beautiful.bg_focus or "#ffcb60" - - cr:set_source(color(bg)) - cr:paint() - - wb:set_bgimage(img) -end - -local function apply_mouse_mode(self) - local w = self:get_wibox() - local align = self._private.align - local real_placement = align_convert[align] - - a_placement[real_placement](w, { - parent = capi.mouse, - offset = offset[align] - }) -end - -local function apply_outside_mode(self) - local w = self:get_wibox() - - local _, position = a_placement.next_to(w, { - geometry = self._private.widget_geometry, - preferred_positions = self.preferred_positions, - honor_workarea = true, - }) - - if position ~= self.current_position then - -- Re-apply the shape. - apply_shape(self) - end - - self.current_position = position -end - --- Place the tooltip under the mouse. --- --- @tparam tooltip self A tooltip object. -local function set_geometry(self) - -- calculate width / height - local n_w, n_h = self.textbox:get_preferred_size(mouse.screen) - n_w = n_w + self.marginbox.left + self.marginbox.right - n_h = n_h + self.marginbox.top + self.marginbox.bottom - - local w = self:get_wibox() - w:geometry({ width = n_w, height = n_h }) - - if self._private.shape then - apply_shape(self) - end - - local mode = self.mode - - if mode == "outside" and self._private.widget_geometry then - apply_outside_mode(self) - else - apply_mouse_mode(self) - end - - a_placement.no_offscreen(w) -end - --- Show a tooltip. --- --- @tparam tooltip self The tooltip to show. -local function show(self) - -- do nothing if the tooltip is already shown - if self._private.visible then return end - if self.timer then - if not self.timer.started then - self:timer_function() - self.timer:start() - end - end - set_geometry(self) - self.wibox.visible = true - self._private.visible = true - self:emit_signal("property::visible") -end - --- Hide a tooltip. --- --- @tparam tooltip self The tooltip to hide. -local function hide(self) - -- do nothing if the tooltip is already hidden - if not self._private.visible then return end - if self.timer then - if self.timer.started then - self.timer:stop() - end - end - self.wibox.visible = false - self._private.visible = false - self:emit_signal("property::visible") -end - ---- The wibox. --- @property wibox --- @param `wibox` - -function tooltip:get_wibox() - if self._private.wibox then - return self._private.wibox - end - - local wb = wibox(self.wibox_properties) - wb:set_widget(self.marginbox) - - -- Close the tooltip when clicking it. This gets done on release, to not - -- emit the release event on an underlying object, e.g. the titlebar icon. - wb:buttons(abutton({}, 1, nil, self.hide)) - - self._private.wibox = wb - - return wb -end - ---- Is the tooltip visible? --- @property visible --- @param boolean - -function tooltip:get_visible() - return self._private.visible -end - -function tooltip:set_visible(value) - if self._private.visible == value then return end - - if value then - show(self) - else - hide(self) - end -end - ---- The horizontal alignment. --- --- The following values are valid: --- --- * top_left --- * left --- * bottom_left --- * right --- * top_right --- * bottom_right --- * bottom --- * top --- --- @property align --- @see beautiful.tooltip_align - ---- The default tooltip alignment. --- @beautiful beautiful.tooltip_align --- @param string --- @see align - -function tooltip:get_align() - return self._private.align -end - -function tooltip:set_align(value) - if not align_convert[value] then - return - end - - self._private.align = value - - set_geometry(self) - self:emit_signal("property::align") -end - ---- The shape of the tooltip window. --- If the shape require some parameters, use `set_shape`. --- @property shape --- @see gears.shape --- @see set_shape --- @see beautiful.tooltip_shape - ---- Set the tooltip shape. --- All other arguments will be passed to the shape function. --- @tparam gears.shape s The shape --- @see shape --- @see gears.shape -function tooltip:set_shape(s, ...) - self._private.shape = s - self._private.shape_args = {...} - apply_shape(self) -end - ---- Set the tooltip positioning mode. --- This affects how the tooltip is placed. By default, the tooltip is `align`ed --- close to the mouse cursor. It is also possible to place the tooltip relative --- to the widget geometry. --- --- Valid modes are: --- --- * "mouse": Next to the mouse cursor --- * "outside": Outside of the widget --- --- @property mode --- @param string - -function tooltip:set_mode(mode) - self._private.mode = mode - - set_geometry(self) - self:emit_signal("property::mode") -end - -function tooltip:get_mode() - return self._private.mode or "mouse" -end - ---- The preferred positions when in `outside` mode. --- --- If the tooltip fits on multiple sides of the drawable, then this defines the --- priority --- --- The default is: --- --- {"top", "right", "left", "bottom"} --- --- @property preferred_positions --- @tparam table preferred_positions The position, ordered by priorities - -function tooltip:get_preferred_positions() - return self._private.preferred_positions or - {"top", "right", "left", "bottom"} -end - -function tooltip:set_preferred_positions(value) - self._private.preferred_positions = value - - set_geometry(self) -end - ---- Change displayed text. --- --- @property text --- @tparam tooltip self The tooltip object. --- @tparam string text New tooltip text, passed to --- `wibox.widget.textbox.set_text`. - -function tooltip:set_text(text) - self.textbox:set_text(text) - if self._private.visible then - set_geometry(self) - end -end - ---- Change displayed markup. --- --- @property markup --- @tparam tooltip self The tooltip object. --- @tparam string text New tooltip markup, passed to --- `wibox.widget.textbox.set_markup`. - -function tooltip:set_markup(text) - self.textbox:set_markup(text) - if self._private.visible then - set_geometry(self) - end -end - ---- Change the tooltip's update interval. --- --- @property timeout --- @tparam tooltip self A tooltip object. --- @tparam number timeout The timeout value. - -function tooltip:set_timeout(timeout) - if self.timer then - self.timer.timeout = timeout - end -end - ---- Add tooltip to an object. --- --- @tparam tooltip self The tooltip. --- @tparam gears.object obj An object with `mouse::enter` and --- `mouse::leave` signals. --- @function add_to_object -function tooltip:add_to_object(obj) - if not obj then return end - - obj:connect_signal("mouse::enter", self.show) - obj:connect_signal("mouse::leave", self.hide) -end - ---- Remove tooltip from an object. --- --- @tparam tooltip self The tooltip. --- @tparam gears.object obj An object with `mouse::enter` and --- `mouse::leave` signals. --- @function remove_from_object -function tooltip:remove_from_object(obj) - obj:disconnect_signal("mouse::enter", self.show) - obj:disconnect_signal("mouse::leave", self.hide) -end - --- Tooltip can be applied to both widgets, wibox and client, their geometry --- works differently. -local function get_parent_geometry(arg1, arg2) - if type(arg2) == "table" and arg2.width then - return arg2 - elseif type(arg1) == "table" and arg1.width then - return arg1 - end -end - ---- Create a new tooltip and link it to a widget. --- Tooltips emit `property::visible` when their visibility changes. --- @tparam table args Arguments for tooltip creation. --- @tparam function args.timer_function A function to dynamically set the --- tooltip text. Its return value will be passed to --- `wibox.widget.textbox.set_markup`. --- @tparam[opt=1] number args.timeout The timeout value for --- `timer_function`. --- @tparam[opt] table args.objects A list of objects linked to the tooltip. --- @tparam[opt] number args.delay_show Delay showing the tooltip by this many --- seconds. --- @tparam[opt=apply_dpi(5)] integer args.margin_leftright The left/right margin for the text. --- @tparam[opt=apply_dpi(3)] integer args.margin_topbottom The top/bottom margin for the text. --- @tparam[opt=nil] gears.shape args.shape The shape --- @treturn awful.tooltip The created tooltip. --- @see add_to_object --- @see timeout --- @see text --- @see markup --- @function awful.tooltip -function tooltip.new(args) - local self = object { - enable_properties = true, - } - - rawset(self,"_private", {}) - - self._private.visible = false - self._private.align = args.align or beautiful.tooltip_align or "right" - self._private.shape = args.shape or beautiful.tooltip_shape - or shape.rectangle - - -- private data - if args.delay_show then - local delay_timeout - - delay_timeout = timer { timeout = args.delay_show } - delay_timeout:connect_signal("timeout", function () - show(self) - delay_timeout:stop() - end) - - function self.show(other, geo) - -- Auto detect clients and wiboxes - if other.drawable or other.pid then - geo = other:geometry() - end - - -- Cache the geometry in case it is needed later - self._private.widget_geometry = get_parent_geometry(other, geo) - - if not delay_timeout.started then - delay_timeout:start() - end - end - function self.hide() - if delay_timeout.started then - delay_timeout:stop() - end - hide(self) - end - else - function self.show(other, geo) - -- Auto detect clients and wiboxes - if other.drawable or other.pid then - geo = other:geometry() - end - - -- Cache the geometry in case it is needed later - self._private.widget_geometry = get_parent_geometry(other, geo) - - show(self) - end - function self.hide() - hide(self) - end - end - - -- export functions - util.table.crush(self, tooltip, true) - - -- setup the timer action only if needed - if args.timer_function then - self.timer = timer { timeout = args.timeout and args.timeout or 1 } - self.timer_function = function() - self:set_markup(args.timer_function()) - end - self.timer:connect_signal("timeout", self.timer_function) - end - - local fg = beautiful.tooltip_fg or beautiful.fg_focus or "#000000" - local font = beautiful.tooltip_font or beautiful.font - - -- Set default properties - self.wibox_properties = { - visible = false, - ontop = true, - border_width = 0, - fg = fg, - bg = color.transparent, - opacity = beautiful.tooltip_opacity or 1, - } - - self.textbox = textbox() - self.textbox:set_font(font) - - -- Add margin. - local m_lr = args.margin_leftright or dpi(5) - local m_tb = args.margin_topbottom or dpi(3) - self.marginbox = wibox.container.margin(self.textbox, m_lr, m_lr, m_tb, m_tb) - - -- Add tooltip to objects - if args.objects then - for _, obj in ipairs(args.objects) do - self:add_to_object(obj) - end - end - - -- Apply the properties - for k, v in pairs(args) do - if tooltip["set_"..k] then - self[k] = v - end - end - - return self -end - -function tooltip.mt:__call(...) - return tooltip.new(...) -end - -return setmetatable(tooltip, tooltip.mt) - --- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80 |