Add a BoxShadow element

This intends to provide a configurable rectangular "drop shadow". The
API is modeled after CSS/HTML5 Canvas where the element can be "bound"
to an existing rectangular shape (geometry and radius), the offset can
be used to place the shadow and color and blur configure the shadow.

The shadow's color fades into transparent.

TODO (in subsequent changes):
 * Documentation
 * Qt implementation
This commit is contained in:
Simon Hausmann 2021-01-25 12:08:29 +01:00
parent 0cb51a986f
commit 628e6fdb38
8 changed files with 171 additions and 12 deletions

View file

@ -925,6 +925,79 @@ impl ItemRenderer for GLItemRenderer {
})
}
fn draw_box_shadow(
&mut self,
pos: Point,
box_shadow: std::pin::Pin<&sixtyfps_corelib::items::BoxShadow>,
) {
// TODO: cache path in item to avoid re-tesselation
let blur = box_shadow.blur();
let shadow_outer_rect: euclid::Rect<f32, euclid::UnknownUnit> = euclid::rect(
box_shadow.x() + box_shadow.offset_x() - blur / 2.,
box_shadow.y() + box_shadow.offset_y() - blur / 2.,
box_shadow.width() + blur,
box_shadow.height() + blur,
);
let shadow_inner_rect: euclid::Rect<f32, euclid::UnknownUnit> = euclid::rect(
box_shadow.x() + box_shadow.offset_x() + blur / 2.,
box_shadow.y() + box_shadow.offset_y() + blur / 2.,
box_shadow.width() - blur,
box_shadow.height() - blur,
);
let shadow_fill_rect: euclid::Rect<f32, euclid::UnknownUnit> = euclid::rect(
shadow_outer_rect.min_x() + blur / 2.,
shadow_outer_rect.min_y() + blur / 2.,
box_shadow.width(),
box_shadow.height(),
);
let paint = femtovg::Paint::box_gradient(
shadow_fill_rect.min_x(),
shadow_fill_rect.min_y(),
shadow_fill_rect.width(),
shadow_fill_rect.height(),
box_shadow.radius(),
box_shadow.blur(),
box_shadow.color().into(),
Color::from_argb_u8(0, 0, 0, 0).into(),
);
let mut path = femtovg::Path::new();
path.rounded_rect(
shadow_outer_rect.min_x(),
shadow_outer_rect.min_y(),
shadow_outer_rect.width(),
shadow_outer_rect.height(),
box_shadow.radius(),
);
path.rect(
shadow_inner_rect.min_x(),
shadow_inner_rect.min_y(),
shadow_inner_rect.width(),
shadow_inner_rect.height(),
);
path.solidity(femtovg::Solidity::Hole);
self.shared_data.canvas.borrow_mut().save_with(|canvas| {
canvas.translate(pos.x, pos.y);
canvas.fill_path(&mut path, paint);
let mut shadow_inner_path = femtovg::Path::new();
shadow_inner_path.rect(
shadow_inner_rect.min_x(),
shadow_inner_rect.min_y(),
shadow_inner_rect.width(),
shadow_inner_rect.height(),
);
let fill = femtovg::Paint::color(box_shadow.color().into());
canvas.fill_path(&mut shadow_inner_path, fill);
})
}
fn combine_clip(&mut self, pos: Point, clip: std::pin::Pin<&sixtyfps_corelib::items::Clip>) {
let clip_rect = clip.geometry().translate([pos.x, pos.y].into());
self.shared_data.canvas.borrow_mut().intersect_scissor(
@ -943,6 +1016,10 @@ impl ItemRenderer for GLItemRenderer {
self.shared_data.canvas.borrow_mut().restore();
}
fn scale_factor(&self) -> f32 {
self.scale_factor
}
fn draw_cached_pixmap(
&mut self,
item_cache: &CachedRenderingData,
@ -981,10 +1058,6 @@ impl ItemRenderer for GLItemRenderer {
canvas.fill_path(&mut path, fill_paint);
}
fn scale_factor(&self) -> f32 {
self.scale_factor
}
fn as_any(&mut self) -> &mut dyn std::any::Any {
self
}