use crate::view::context::ElementContext;
use crate::view::style::Style;
use crate::view::theme::Token;
use crate::core::{Bounds, Corners, Edges, Pixels, Point, Rgba, Size};
use crate::gpu::text::TextPlacement;
use crate::gpu::{ImageSource, MonochromeSprite, Quad, Shadow, ShapedText, Underline};
impl ElementContext<'_> {
pub fn paint_box(&mut self, bounds: Bounds, style: &Style) {
let mask = self.mask();
let opacity = style.opacity.unwrap_or(1.0);
let radius = style.radius.unwrap_or_default().min(bounds.size.width / 2.0).min(bounds.size.height / 2.0);
let corners = Corners::all(radius);
for layer in style.shadow.iter().flat_map(|shadows| shadows.layers().iter().rev()) {
let color = layer.color.map_or(self.theme.shadow, |spec| self.theme.resolve(spec));
let color = color.with_alpha(color.a * layer.strength * opacity);
let spread = Pixels(layer.spread);
let grown = Size::new(
Pixels((bounds.size.width.0 + spread.0 * 2.0).max(0.0)),
Pixels((bounds.size.height.0 + spread.0 * 2.0).max(0.0)),
);
let origin = bounds.origin + layer.offset - Point::new(spread, spread);
let corners = Corners::all(Pixels((radius.0 + spread.0).max(0.0)));
self.frame.scene.insert_shadow(Shadow::new(Bounds::new(origin, grown), mask, color, corners, layer.blur));
}
let background = style.background.map(|spec| self.theme.resolve(spec));
let border_width = style.border_width.unwrap_or_default();
if background.is_none() && border_width == Pixels::ZERO {
return;
}
let fill = background.unwrap_or(Rgba::TRANSPARENT);
let mut quad = Quad::new(bounds, mask, fade(fill, opacity)).corners(corners);
if let (Some((angle, end)), Some(_)) = (style.gradient, background) {
quad = quad.gradient(angle, fade(self.theme.resolve(end), opacity));
}
if border_width > Pixels::ZERO {
let border_color =
style.border_color.map_or(self.theme.color(Token::Border), |spec| self.theme.resolve(spec));
quad = quad.border(Edges::all(border_width), fade(border_color, opacity));
}
self.frame.scene.insert_quad(quad);
}
pub fn fill_rect(&mut self, bounds: Bounds, color: Rgba) {
let quad = Quad::new(bounds, self.mask(), color);
self.frame.scene.insert_quad(quad);
}
pub fn paint_gradient_rect(&mut self, bounds: Bounds, angle: f32, from: Rgba, to: Rgba) {
let quad = Quad::new(bounds, self.mask(), from).gradient(angle, to);
self.frame.scene.insert_quad(quad);
}
pub fn paint_underline(&mut self, bounds: Bounds, color: Rgba, wavy: bool) {
let underline = Underline::new(bounds, self.mask(), color, 1.0, wavy);
self.frame.scene.insert_underline(underline);
}
pub fn paint_outline(&mut self, bounds: Bounds, color: Rgba, radius: Pixels) {
let quad = Quad::new(bounds, self.mask(), Rgba::TRANSPARENT)
.corners(Corners::all(radius))
.border(Edges::all(Pixels(1.0)), color);
self.frame.scene.insert_quad(quad);
}
pub fn paint_rounded_rect(&mut self, bounds: Bounds, color: Rgba, radius: Pixels) {
let quad = Quad::new(bounds, self.mask(), color).corners(Corners::all(radius));
self.frame.scene.insert_quad(quad);
}
pub fn paint_text(&mut self, shaped: &ShapedText, origin: Point, color: Rgba) {
let placement = TextPlacement { origin, color, clip: self.mask(), scale: self.scale };
let Some(target) = self.glyphs.as_mut() else {
return;
};
self.text.paint(shaped, &placement, target, &mut self.frame.scene);
}
pub fn measure(&self, shaped: &ShapedText) -> Size {
shaped.size
}
pub fn paint_icon(&mut self, name: &'static str, svg: &'static [u8], bounds: Bounds, color: Rgba) {
let size_px = (bounds.size.width.0.max(bounds.size.height.0) * self.scale).round() as u32;
let mask = self.mask();
let Some(target) = self.glyphs.as_mut() else { return };
if let Some(tile) = self.sprites.icon(name, svg, size_px, target) {
self.frame.scene.insert_monochrome(MonochromeSprite::new(bounds, mask, tile.uv, color));
}
}
pub fn forget_image(&mut self, id: u64) {
let Some(target) = self.glyphs.as_mut() else { return };
self.sprites.forget_image(id, target);
}
pub fn paint_image(&mut self, source: &ImageSource, bounds: Bounds) {
let mask = self.mask();
let visible = mask.intersect(&bounds);
if visible.size.width <= Pixels::ZERO || visible.size.height <= Pixels::ZERO {
return;
}
let Some(target) = self.glyphs.as_mut() else { return };
if let Some(tile) = self.sprites.image(source, target) {
self.frame.scene.insert_polychrome(MonochromeSprite::new(
bounds,
mask,
tile.uv,
Rgba::new(1.0, 1.0, 1.0, 1.0),
));
}
}
}
fn fade(color: Rgba, opacity: f32) -> Rgba {
color.with_alpha(color.a * opacity)
}