Last active
October 27, 2021 03:46
-
-
Save Elv13/9fa2be8b2338c34fa9e8cb18c4cc01c3 to your computer and use it in GitHub Desktop.
An AwesomeWM "wibox" container to draw an inner shadow shaped like a rounded rectangle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local cairo = require("lgi").cairo | |
local gears = require("gears") | |
local wibox = require("wibox") | |
local inner_shadow = {} | |
function inner_shadow:layout(context, width, height) | |
if not self._private.widget then return end | |
local offset = (self._private.border_width or 0) | |
+ (self._private.shadow_width or 5) | |
return {wibox.widget.base.place_widget_at( | |
self._private.widget, offset, offset, width-2*offset, height-2*offset | |
)} | |
end | |
function inner_shadow:fit(context, width, height) | |
if not self._private.widget then return 0, 0 end | |
local fill, w, h = self._private.fill, wibox.widget.base.fit_widget( | |
self, context, self._private.widget, width, height | |
) | |
return fill and width or w, fill and height or h | |
end | |
local function init_pattern(br, sh, bw, col) | |
local ret, off, r, g, b = {}, 2*sh - 2*bw, gears.color.parse_color(col) | |
-- Matrix with all pattern parameters | |
local pos = { | |
{br, br, 0 , sh , 0 , 0 }, {0 , br, off, 0 , sh+off, 0 }, | |
{0 , 0 , 0 , off, 0 , sh+off }, {br, 0 , sh , 0 , 0 , 0 }} | |
for i=1, 4 do | |
-- Radial (corners) | |
ret[i] = cairo.Pattern.create_radial( | |
pos[i][1], pos[i][2], br-sh, pos[i][1], pos[i][2], br | |
) | |
-- Linear (sides) | |
ret[i+4] = cairo.Pattern.create_linear( | |
pos[i][3], pos[i][4], pos[i][5], pos[i][6] | |
) | |
end | |
for _, p in ipairs(ret) do | |
p:set_extend(cairo.Extend.REPEAT) | |
p:add_color_stop_rgba(0, r, g, b, 0) | |
p:add_color_stop_rgba(1, r, g, b, 1) | |
end | |
return ret | |
end | |
function inner_shadow:before_draw_children(_, cr, w, h) | |
local border = self._private.shadow_width or 5 | |
local rad = self._private.corner_radius or 15 | |
local bw = self._private.border_width or 0 | |
cr:save() | |
-- Shrink the rectangle by the outer border to make the code simpler | |
w, h = w - 2*bw, h - 2*bw | |
gears.shape.rounded_rect(cr, w+bw, h+bw, rad) | |
cr:clip() | |
self._private.patterns = self._private.patterns or init_pattern( | |
rad, border, bw, self._private.shadow_color or "#ff0000" | |
) | |
local tr = {{bw , bw , rad , 0 , w-2*rad, border }, | |
{w-rad , 0 , w-border, rad , border , h-2*rad}, | |
{0 , w-rad, rad , h-border, w-2*rad, border }, | |
{-w+rad, 0 , 0 , rad , border , h-2*rad}} | |
-- Corners | |
for k, t in ipairs(tr) do | |
cr:translate(t[1], t[2]) | |
cr:set_source(self._private.patterns[k]) | |
cr:rectangle(0,0,rad,rad) | |
cr:fill() | |
end | |
cr:translate(0, -h+rad) | |
-- Sides | |
for i=1, 4 do | |
cr:set_source(self._private.patterns[4+i]) | |
cr:rectangle(tr[i][3], tr[i][4], tr[i][5], tr[i][6]) | |
cr:fill() | |
end | |
-- Draw the outer border | |
if bw > 0 then | |
cr:reset_clip() | |
cr:translate(-bw/2, -bw/2) | |
gears.shape.rounded_rect(cr, w+bw, h+bw, rad) | |
cr:set_source(gears.color(self._private.border_color or "#00ff00")) | |
cr:set_line_width(bw) | |
cr:stroke() | |
end | |
cr:restore() | |
end | |
function inner_shadow:get_children() | |
return {self._private.widget} | |
end | |
function inner_shadow:set_children(children) | |
self:set_widget(children[1]) | |
end | |
function inner_shadow:reset() | |
self:set_widget(nil) | |
end | |
for _, prop in ipairs { "fill", "shadow_color", "border_color", "widget", | |
"border_width", "shadow_width", "corner_radius" } do | |
inner_shadow["set_"..prop] = function(self, value) | |
self._private[prop], self._private.patterns = value, nil | |
self:emit_signal("widget::redraw_needed") | |
self:emit_signal("widget::layout_needed") | |
end | |
end | |
return function(widget, halign, valign) | |
local ret = wibox.widget.base.make_widget(nil, nil, {enable_properties = true}) | |
return gears.table.crush(ret, inner_shadow, true) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment