@@ -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 ))
0 commit comments