Skip to content

Commit

Permalink
shape: Add a "solid shadow" shape. (#3489)
Browse files Browse the repository at this point in the history
This is an useful client shape to get "client side solid shadows".
  • Loading branch information
Elv13 authored Oct 16, 2022
1 parent 963622a commit 26032bf
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
70 changes: 70 additions & 0 deletions lib/gears/shape.lua
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,76 @@ function module.arc(cr, width, height, thickness, start_angle, end_angle, start_
cr:close_path()
end

--- Overlap 2 rectangles to emulate a shadow effect.
--
-- This is intended to be used with either the `wibox.container.margin` or
-- the `client.shape` to implement MS-DOS and TWM MenuShadowColor "classic"
-- shadows.
--
-- Warning: If `x_offset` or `y_offset` are greater than the width or height
-- respectively, strange thing will happen.
--
-- @DOC_gears_shape_solid_rectangle_shadow_EXAMPLE@
--
-- @staticfct gears.shape.solid_rectangle_shadow
-- @param cr A cairo context
-- @tparam number width The shape width
-- @tparam number height The shape height
-- @tparam[opt=5] number x_offset The shadow area horizontal offset.
-- @tparam[opt=5] number y_offset The shadow area vertical offset.
function module.solid_rectangle_shadow(cr, w, h, x_offset, y_offset)
x_offset, y_offset = x_offset or 5, y_offset or 5
w, h = w - math.abs(x_offset), h - math.abs(y_offset)

-- Get rid of the corner case first.
if x_offset == 0 and y_offset == 0 then return module.rectangle(cr, w, h) end

-- This leaves 2 possibilities, "hole" at top-left or top-right.

-- Gather the main rectangle geometry.
local rect1 = {x0=0, y0=0, x1=w, y1=h}
local rect2 = {x0=x_offset, y0=y_offset, x1=w + x_offset, y1=h + y_offset}

-- Normalize (shift) to {0, 0} -> {w, h}
if x_offset < 0 then
rect1.x0, rect1.x1 = rect1.x0 - x_offset, rect1.x1 - x_offset
rect2.x0, rect2.x1 = rect2.x0 - x_offset, rect2.x1 - x_offset
end
if y_offset < 0 then
rect1.y0, rect1.y1 = rect1.y0 - y_offset, rect1.y1 - y_offset
rect2.y0, rect2.y1 = rect2.y0 - y_offset, rect2.y1 - y_offset
end

-- Swap the rectangles if needed.
if y_offset < 0 then
rect1, rect2 = rect2, rect1
end

if rect1.x0 > rect2.x0 then
-- cut at top-right
cr:move_to(rect1.x0, rect1.y0)
cr:line_to(rect1.x1, rect1.y0)
cr:line_to(rect1.x1, rect1.y1)
cr:line_to(rect2.x1, rect1.y1)
cr:line_to(rect2.x1, rect2.y1)
cr:line_to(rect2.x0, rect2.y1)
cr:line_to(rect2.x0, rect2.y0)
cr:line_to(rect1.x0, rect2.y0)
cr:close_path()
else
-- cut at top-left
cr:move_to(rect1.x0, rect1.y0)
cr:line_to(rect1.x1, rect1.y0)
cr:line_to(rect1.x1, rect2.y0)
cr:line_to(rect2.x1, rect2.y0)
cr:line_to(rect2.x1, rect2.y1)
cr:line_to(rect2.x0, rect2.y1)
cr:line_to(rect2.x0, rect1.y1)
cr:line_to(rect1.x0, rect1.y1)
cr:close_path()
end
end

--- A partial rounded bar. How much of the rounded bar is visible depends on
-- the given percentage value.
--
Expand Down
12 changes: 12 additions & 0 deletions tests/examples/gears/shape/solid_rectangle_shadow.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--DOC_GEN_IMAGE --DOC_HIDE
local shape,cr,show = ... --DOC_HIDE

shape.solid_rectangle_shadow(cr, 70, 70, 10, 5)
show(cr) --DOC_HIDE

shape.solid_rectangle_shadow(cr, 70, 70, 5, -10)
show(cr) --DOC_HIDE

shape.solid_rectangle_shadow(cr, 70, 70, 30, -30)
show(cr) --DOC_HIDE
--DOC_HIDE vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

1 comment on commit 26032bf

@charbelnicolas
Copy link

@charbelnicolas charbelnicolas commented on 26032bf Oct 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, it seems like this commit triggered a new warning at compile time (something about a noreturn)

Please sign in to comment.