Skip to content

Commit 22e5c7c

Browse files
committed
Implemented shadows for overlays
1 parent 633adc8 commit 22e5c7c

File tree

3 files changed

+222
-1
lines changed

3 files changed

+222
-1
lines changed

include/lsp-plug.in/tk/widgets/containers/Overlay.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ namespace lsp
4444
prop::Integer sBorderRadius; // Border radius
4545
prop::Integer sBorderSize; // Border width
4646
prop::Color sBorderColor; // Border color
47+
prop::Integer sShadowSize; // Shadow size
48+
prop::Color sShadowStart; // Shadow start color
49+
prop::Color sShadowEnd; // Shadow end color
4750
LSP_TK_STYLE_DEF_END
4851
}
4952

@@ -66,6 +69,8 @@ namespace lsp
6669
public:
6770
static const w_class_t metadata;
6871

72+
friend class Window;
73+
6974
protected:
7075
Widget *wWidget;
7176

@@ -79,12 +84,30 @@ namespace lsp
7984
prop::Integer sBorderRadius; // Border radius
8085
prop::Integer sBorderSize; // Border width
8186
prop::Color sBorderColor; // Border color
87+
prop::Integer sShadowSize; // Shadow size
88+
prop::Color sShadowStart; // Shadow start color
89+
prop::Color sShadowEnd; // Shadow end color
8290

8391
overlay_position_t pPosFunc; // Position calculation function
8492
void *pPosData; // Position data function
8593

8694
protected:
8795
void do_destroy();
96+
void draw_shadow_segment(
97+
ws::ISurface *s,
98+
float x1, float y1,
99+
float x2, float y2,
100+
bool start, bool end,
101+
float width, float radius);
102+
103+
void draw_shadow_ring(
104+
ws::ISurface *s,
105+
float xc, float yc,
106+
float x1, float y1,
107+
float x2, float y2,
108+
float angle);
109+
110+
void draw_shadow(ws::ISurface *s);
88111

89112
protected:
90113
virtual Widget *find_widget(ssize_t x, ssize_t y) override;
@@ -115,6 +138,9 @@ namespace lsp
115138
LSP_TK_PROPERTY(Integer, border_radius, &sBorderRadius)
116139
LSP_TK_PROPERTY(Integer, border_size, &sBorderSize)
117140
LSP_TK_PROPERTY(Color, border_color, &sBorderColor)
141+
LSP_TK_PROPERTY(Integer, shadow_size, &sShadowSize)
142+
LSP_TK_PROPERTY(Color, shadow_start, &sShadowStart)
143+
LSP_TK_PROPERTY(Color, shadow_end, &sShadowEnd)
118144

119145
public:
120146
virtual void draw(ws::ISurface *s, bool force) override;

src/main/widgets/containers/Overlay.cpp

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ namespace lsp
4141
sBorderRadius.bind("border.radius", this);
4242
sBorderSize.bind("border.size", this);
4343
sBorderColor.bind("border.color", this);
44+
sShadowSize.bind("shadow.size", this);
45+
sShadowStart.bind("shadow.start", this);
46+
sShadowEnd.bind("shadow.end", this);
4447

4548
// Configure
4649
sTransparency.set(0.25f);
@@ -53,6 +56,9 @@ namespace lsp
5356
sBorderRadius.set(12);
5457
sBorderSize.set(0);
5558
sBorderColor.set_rgb24(0x000000);
59+
sShadowSize.set(0);
60+
sShadowStart.set_rgba32(0x00000000);
61+
sShadowEnd.set_rgba32(0xff000000);
5662

5763
// Override
5864
sLayout.override();
@@ -74,7 +80,10 @@ namespace lsp
7480
sBorderRounding(&sProperties),
7581
sBorderRadius(&sProperties),
7682
sBorderSize(&sProperties),
77-
sBorderColor(&sProperties)
83+
sBorderColor(&sProperties),
84+
sShadowSize(&sProperties),
85+
sShadowStart(&sProperties),
86+
sShadowEnd(&sProperties)
7887
{
7988
pClass = &metadata;
8089

@@ -105,6 +114,9 @@ namespace lsp
105114
sBorderRadius.bind("border.radius", &sStyle);
106115
sBorderSize.bind("border.size", &sStyle);
107116
sBorderColor.bind("border.color", &sStyle);
117+
sShadowSize.bind("shadow.size", &sStyle);
118+
sShadowStart.bind("shadow.start", &sStyle);
119+
sShadowEnd.bind("shadow.end", &sStyle);
108120

109121
return STATUS_OK;
110122
}
@@ -255,6 +267,168 @@ namespace lsp
255267
}
256268
}
257269

270+
void Overlay::draw_shadow_ring(
271+
ws::ISurface *s,
272+
float xc, float yc,
273+
float x1, float y1,
274+
float x2, float y2,
275+
float angle)
276+
{
277+
float vx1 = x1 - xc;
278+
float vy1 = y1 - yc;
279+
float vx2 = x2 - xc;
280+
float vy2 = y2 - yc;
281+
const float r1 = sqrtf(vx1*vx1 + vy1*vy1);
282+
283+
const size_t count = lsp_max(fabsf(r1 * angle * 0.5f), 2.0f);
284+
const float phi = angle / float(count);
285+
286+
const float dx = cosf(phi);
287+
const float dy = sinf(phi);
288+
289+
for (size_t i=0; i < count; ++i)
290+
{
291+
float nvx1 = vx1*dx - vy1*dy;
292+
float nvy1 = vx1*dy + vy1*dx;
293+
float nvx2 = vx2*dx - vy2*dy;
294+
float nvy2 = vx2*dy + vy2*dx;
295+
vx1 = nvx1;
296+
vy1 = nvy1;
297+
vx2 = nvx2;
298+
vy2 = nvy2;
299+
300+
const float x3 = xc + vx1;
301+
const float y3 = yc + vy1;
302+
const float x4 = xc + vx2;
303+
const float y4 = yc + vy2;
304+
305+
// Fill main part
306+
ws::IGradient *g = s->linear_gradient(x1, y1, x2, y2);
307+
if (g == NULL)
308+
return;
309+
lsp_finally { delete g; };
310+
311+
// Prepare colors
312+
g->set_start(sShadowStart);
313+
g->set_stop(sShadowEnd, 1.0f);
314+
315+
s->fill_triangle(g, x1, y1, x2, y2, x4, y4);
316+
s->fill_triangle(g, x1, y1, x4, y4, x3, y3);
317+
318+
x1 = x3;
319+
y1 = y3;
320+
x2 = x4;
321+
y2 = y4;
322+
}
323+
}
324+
325+
void Overlay::draw_shadow_segment(
326+
ws::ISurface *s,
327+
float x1, float y1,
328+
float x2, float y2,
329+
bool start, bool end,
330+
float width, float radius)
331+
{
332+
// Compute direction
333+
float dx = (x2 - x1);
334+
float dy = (y2 - y1);
335+
const float dw = sqrtf(dx*dx + dy*dy);
336+
if (dw <= 0.05f)
337+
return;
338+
const float rdw = 1.0f / dw;
339+
340+
dx *= rdw;
341+
dy *= rdw;
342+
const float rdx = radius * dx;
343+
const float rdy = radius * dy;
344+
345+
dx *= width;
346+
dy *= width;
347+
348+
// Draw start segment
349+
float x0, y0, x3, y3;
350+
351+
if ((start) && (radius >= 1.0f))
352+
{
353+
x1 += rdx;
354+
y1 += rdy;
355+
x0 = x1 + dy;
356+
y0 = y1 - dx;
357+
358+
draw_shadow_ring(s, x1 - rdy, y1 + rdx, x1, y1, x0, y0, -0.25f * M_PI);
359+
}
360+
else
361+
{
362+
x0 = x1 + dy - dx;
363+
y0 = y1 - dx - dy;
364+
}
365+
366+
if ((end) && (radius >= 1.0f))
367+
{
368+
x2 -= rdx;
369+
y2 -= rdy;
370+
x3 = x2 + dy;
371+
y3 = y2 - dx;
372+
373+
draw_shadow_ring(s, x2 - rdy, y2 + rdx, x2, y2, x3, y3, 0.25f * M_PI);
374+
}
375+
else
376+
{
377+
x3 = x2 + dy + dx;
378+
y3 = y2 - dx + dy;
379+
}
380+
381+
// Fill main part
382+
ws::IGradient *g = s->linear_gradient(x1, y1, x1 + dy, y1 - dx);
383+
if (g != NULL)
384+
{
385+
lsp_finally { delete g; };
386+
387+
// Prepare colors
388+
g->set_start(sShadowStart);
389+
g->set_stop(sShadowEnd, 1.0f);
390+
391+
s->fill_triangle(g, x1, y1, x0, y0, x3, y3);
392+
s->fill_triangle(g, x1, y1, x3, y3, x2, y2);
393+
}
394+
}
395+
396+
void Overlay::draw_shadow(ws::ISurface *s)
397+
{
398+
// Check that we need to draw shadow
399+
const float scaling = lsp_max(0.0f, sScaling.get());
400+
const size_t shsize = lsp_max(0.0f, sShadowSize.get() * scaling);
401+
if (shsize < 1)
402+
return;
403+
404+
// Compute shadow parameters
405+
const size_t bround = sBorderRounding.corners();
406+
const size_t bsize = lsp_max(0, sBorderSize.get());
407+
const size_t radius = lsp_max(0.0f, sBorderRadius.get() * scaling) + bsize;
408+
409+
const float xb = sSize.nLeft;
410+
const float xe = sSize.nLeft + sSize.nWidth;
411+
const float yb = sSize.nTop;
412+
const float ye = sSize.nTop + sSize.nHeight;
413+
414+
draw_shadow_segment(
415+
s, xb, yb, xe, yb,
416+
bround & ws::CORNER_LEFT_TOP, bround & ws::CORNER_RIGHT_TOP,
417+
shsize, radius);
418+
draw_shadow_segment(
419+
s, xe, yb, xe, ye,
420+
bround & ws::CORNER_RIGHT_TOP, bround & ws::CORNER_RIGHT_BOTTOM,
421+
shsize, radius);
422+
draw_shadow_segment(
423+
s, xe, ye, xb, ye,
424+
bround & ws::CORNER_RIGHT_BOTTOM, bround & ws::CORNER_LEFT_BOTTOM,
425+
shsize, radius);
426+
draw_shadow_segment(
427+
s, xb, ye, xb, yb,
428+
bround & ws::CORNER_LEFT_BOTTOM, bround & ws::CORNER_LEFT_TOP,
429+
shsize, radius);
430+
}
431+
258432
status_t Overlay::add(Widget *widget)
259433
{
260434
if ((widget == NULL) || (widget == this))

src/main/widgets/containers/Window.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,27 @@ namespace lsp
400400
if (bs != NULL)
401401
s->draw(bs, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);
402402

403+
// Draw overlay shadows
404+
size_t overlays = 0;
405+
406+
for (size_t i=0, n=vDrawOverlays.size(); i<n; ++i)
407+
{
408+
// Get overlay widget
409+
overlay_t *ovd = vDrawOverlays.get(i);
410+
if (ovd == NULL)
411+
continue;
412+
Overlay *ov = ovd->wWidget;
413+
if (ov == NULL)
414+
continue;
415+
416+
// Draw shadow
417+
ov->draw_shadow(s);
418+
++overlays;
419+
}
420+
421+
if (overlays <= 0)
422+
return;
423+
403424
// Draw overlays
404425
for (size_t i=0, n=vDrawOverlays.size(); i<n; ++i)
405426
{

0 commit comments

Comments
 (0)