270 lines
9.5 KiB
Lua
270 lines
9.5 KiB
Lua
local abutton = require "awful.button"
|
|
local atooltip = require "awful.tooltip"
|
|
local colors = require "awesome-wm-nice.colors"
|
|
local get_font_height = require("beautiful").get_font_height
|
|
local imagebox = require "wibox.widget.imagebox"
|
|
local shapes = require "awesome-wm-nice.shapes"
|
|
local textbox = require "wibox.widget.textbox"
|
|
local wibox = require "wibox"
|
|
local wcontainer_constraint = require "wibox.container.constraint"
|
|
local wcontainer_margin = require "wibox.container.margin"
|
|
local wcontainer_place = require "wibox.container.place"
|
|
|
|
local widgets = {}
|
|
local cache = {}
|
|
|
|
-- Legacy global variables
|
|
local _private = {}
|
|
_private.titlebar_height = 38
|
|
_private.titlebar_font = "Sans 11"
|
|
_private.button_size = 16
|
|
_private.button_margin_horizontal = 5
|
|
-- _private.button_margin_vertical
|
|
_private.button_margin_top = 2
|
|
-- _private.button_margin_bottom = 0
|
|
-- _private.button_margin_left = 0
|
|
-- _private.button_margin_right = 0
|
|
_private.tooltips_enabled = true
|
|
_private.tooltip_messages = {
|
|
close = "close",
|
|
minimize = "minimize",
|
|
maximize_active = "unmaximize",
|
|
maximize_inactive = "maximize",
|
|
floating_active = "enable tiling mode",
|
|
floating_inactive = "enable floating mode",
|
|
ontop_active = "don't keep above other windows",
|
|
ontop_inactive = "keep above other windows",
|
|
sticky_active = "disable sticky mode",
|
|
sticky_inactive = "enable sticky mode",
|
|
}
|
|
_private.tooltip_messages = {
|
|
close = "close",
|
|
minimize = "minimize",
|
|
maximize_active = "unmaximize",
|
|
maximize_inactive = "maximize",
|
|
floating_active = "enable tiling mode",
|
|
floating_inactive = "enable floating mode",
|
|
ontop_active = "don't keep above other windows",
|
|
ontop_inactive = "keep above other windows",
|
|
sticky_active = "disable sticky mode",
|
|
sticky_inactive = "enable sticky mode",
|
|
}
|
|
cache.close_color = "#ee4266"
|
|
cache.minimize_color = "#ffb400"
|
|
cache.maximize_color = "#4CBB17"
|
|
cache.floating_color = "#f6a2ed"
|
|
cache.ontop_color = "#f6a2ed"
|
|
cache.sticky_color = "#f6a2ed"
|
|
local title_color_dark = "#242424"
|
|
local title_color_light = "#fefefa"
|
|
local title_unfocused_opacity = 0.7
|
|
|
|
-- Returns a color that is analogous to the last color returned
|
|
-- To make sure that the "randomly" generated colors look cohesive, only the
|
|
-- first color is truly random, the rest are generated by offseting the hue by
|
|
-- +33 degrees
|
|
local next_color = colors.rand_hex()
|
|
local function get_next_color()
|
|
local prev_color = next_color
|
|
next_color = colors.rotate_hue(prev_color, 33)
|
|
return prev_color
|
|
end
|
|
|
|
-- Returns (or generates) a button image based on the given params
|
|
function widgets.create_button_image(name, is_focused, event, is_on)
|
|
local focus_state = is_focused and "focused" or "unfocused"
|
|
local key_img
|
|
-- If it is a toggle button, then the key has an extra param
|
|
if is_on ~= nil then
|
|
local toggle_state = is_on and "on" or "off"
|
|
key_img = ("%s_%s_%s_%s"):format(name, toggle_state, focus_state, event)
|
|
else
|
|
key_img = ("%s_%s_%s"):format(name, focus_state, event)
|
|
end
|
|
-- If an image already exists, then we are done
|
|
if cache[key_img] then
|
|
return cache[key_img]
|
|
end
|
|
-- The color key just has _color at the end
|
|
local key_color = key_img .. "_color"
|
|
-- If the user hasn't provided a color, then we have to generate one
|
|
if not cache[key_color] then
|
|
local key_base_color = name .. "_color"
|
|
-- Maybe the user has at least provided a base color? If not we just pick a pesudo-random color
|
|
local base_color = cache[key_base_color] or get_next_color()
|
|
cache[key_base_color] = base_color
|
|
local button_color = base_color
|
|
local H = colors.hex2hsv(base_color)
|
|
-- Unfocused buttons are desaturated and darkened (except when they are being hovered over)
|
|
if not is_focused and event ~= "hover" then
|
|
button_color = colors.hsv2hex(H, 0, 50)
|
|
end
|
|
-- Then the color is lightened if the button is being hovered over, or
|
|
-- darkened if it is being pressed, otherwise it is left as is
|
|
button_color = (event == "hover") and colors.lighten(button_color, 25)
|
|
or (event == "press") and colors.darken(
|
|
button_color,
|
|
25
|
|
)
|
|
or button_color
|
|
-- Save the generate color because why not lol
|
|
cache[key_color] = button_color
|
|
end
|
|
local button_size = _private.button_size
|
|
-- If it is a toggle button, we create an outline instead of a filled shape if it is in off state
|
|
-- _private[key_img] = (is_on ~= nil and is_on == false) and
|
|
-- shapes.circle_outline(
|
|
-- _private[key_color], button_size,
|
|
-- _private.button_border_width) or
|
|
-- shapes.circle_filled(
|
|
-- _private[key_color], button_size)
|
|
cache[key_img] = shapes.circle_filled(cache[key_color], button_size)
|
|
return cache[key_img]
|
|
end
|
|
|
|
-- Creates a titlebar button widget
|
|
function widgets.create_titlebar_button(c, name, button_callback, property)
|
|
local button_img = imagebox(nil, false)
|
|
if _private.tooltips_enabled then
|
|
local tooltip = atooltip {
|
|
timer_function = function()
|
|
local prop = name
|
|
.. (
|
|
property
|
|
and (c[property] and "_active" or "_inactive")
|
|
or ""
|
|
)
|
|
return _private.tooltip_messages[prop]
|
|
end,
|
|
delay_show = 0.5,
|
|
margins_leftright = 12,
|
|
margins_topbottom = 6,
|
|
timeout = 0.25,
|
|
align = "bottom_right",
|
|
}
|
|
tooltip:add_to_object(button_img)
|
|
end
|
|
local is_on, is_focused
|
|
local event = "normal"
|
|
local function update()
|
|
is_focused = c.active
|
|
-- If the button is for a property that can be toggled
|
|
if property then
|
|
is_on = c[property]
|
|
button_img.image = widgets.create_button_image(
|
|
name,
|
|
is_focused,
|
|
event,
|
|
is_on
|
|
)
|
|
else
|
|
button_img.image = widgets.create_button_image(
|
|
name,
|
|
is_focused,
|
|
event
|
|
)
|
|
end
|
|
end
|
|
-- Update the button when the client gains/loses focus
|
|
c:connect_signal("unfocus", update)
|
|
c:connect_signal("focus", update)
|
|
-- If the button is for a property that can be toggled, update it accordingly
|
|
if property then
|
|
c:connect_signal("property::" .. property, update)
|
|
end
|
|
-- Update the button on mouse hover/leave
|
|
button_img:connect_signal("mouse::enter", function()
|
|
event = "hover"
|
|
update()
|
|
end)
|
|
button_img:connect_signal("mouse::leave", function()
|
|
event = "normal"
|
|
update()
|
|
end)
|
|
-- The button is updated on both click and release, but the call back is executed on release
|
|
button_img.buttons = abutton({}, abutton.names.LEFT, function()
|
|
event = "press"
|
|
update()
|
|
end, function()
|
|
if button_callback then
|
|
event = "normal"
|
|
button_callback()
|
|
else
|
|
event = "hover"
|
|
end
|
|
update()
|
|
end)
|
|
button_img.id = "button_image"
|
|
update()
|
|
return wibox.widget {
|
|
widget = wcontainer_place,
|
|
{
|
|
widget = wcontainer_margin,
|
|
top = _private.button_margin_top
|
|
or _private.button_margin_vertical
|
|
or _private.button_margin,
|
|
bottom = _private.button_margin_bottom
|
|
or _private.button_margin_vertical
|
|
or _private.button_margin,
|
|
left = _private.button_margin_left
|
|
or _private.button_margin_horizontal
|
|
or _private.button_margin,
|
|
right = _private.button_margin_right
|
|
or _private.button_margin_horizontal
|
|
or _private.button_margin,
|
|
{
|
|
button_img,
|
|
widget = wcontainer_constraint,
|
|
height = _private.button_size,
|
|
width = _private.button_size,
|
|
strategy = "exact",
|
|
},
|
|
},
|
|
}
|
|
end
|
|
|
|
-- Returns a titlebar widget for the given client
|
|
function widgets.create_titlebar_title(c)
|
|
local client_color = c._nice_base_color
|
|
|
|
local title_widget = wibox.widget {
|
|
align = "center",
|
|
ellipsize = "middle",
|
|
opacity = c.active and 1 or title_unfocused_opacity,
|
|
valign = "center",
|
|
widget = textbox,
|
|
}
|
|
|
|
local function update()
|
|
local text_color = colors.is_contrast_acceptable(
|
|
title_color_light,
|
|
client_color
|
|
) and title_color_light or title_color_dark
|
|
title_widget.markup =
|
|
("<span foreground='%s' font='%s'>%s</span>"):format(
|
|
text_color,
|
|
_private.titlebar_font,
|
|
c.name
|
|
)
|
|
end
|
|
c:connect_signal("property::name", update)
|
|
c:connect_signal("unfocus", function()
|
|
title_widget.opacity = title_unfocused_opacity
|
|
end)
|
|
c:connect_signal("focus", function()
|
|
title_widget.opacity = 1
|
|
end)
|
|
update()
|
|
local titlebar_font_height = get_font_height(_private.titlebar_font)
|
|
local leftover_space = _private.titlebar_height - titlebar_font_height
|
|
local margin_vertical = leftover_space > 1 and leftover_space / 2 or 0
|
|
return {
|
|
title_widget,
|
|
widget = wcontainer_margin,
|
|
top = margin_vertical,
|
|
bottom = margin_vertical,
|
|
}
|
|
end
|
|
|
|
return widgets
|