Skip to content

Instantly share code, notes, and snippets.

@Elv13
Last active October 27, 2021 03:46
Show Gist options
  • Save Elv13/9fa2be8b2338c34fa9e8cb18c4cc01c3 to your computer and use it in GitHub Desktop.
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
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