use crate::ast::Style;
use crate::ast::style::BoxSides;
use crate::visual::{Color, FillStrokeStyle, Stroke, VisualElement};
use vello_cpu::kurbo::Rect;
use super::PageContext;
pub(crate) struct BgStyle {
pub color: Color,
pub padding: BoxSides,
pub margin: BoxSides,
}
pub(crate) fn begin_box(
ctx: &mut PageContext,
current_indent: f32,
style: &Style,
) -> (f32, f32, f32, f32) {
ctx.consume_height(style.margin.top);
let content_indent = current_indent + style.margin.left + style.padding.left;
let content_width = ctx.settings.content_width()
- current_indent
- style.margin.left
- style.padding.left
- style.margin.right
- style.padding.right;
let content_start_y = ctx.current_y;
ctx.consume_height(style.padding.top);
(
content_indent,
content_width,
content_start_y,
current_indent,
)
}
pub(crate) fn end_box_content(ctx: &mut PageContext, style: &Style) {
ctx.consume_height(style.padding.bottom);
ctx.consume_height(style.margin.bottom);
}
pub(crate) fn end_box(
ctx: &mut PageContext,
style: &Style,
content_start_y: f32,
prev_indent: f32,
) {
ctx.consume_height(style.padding.bottom);
draw_box_background(ctx, style, content_start_y, prev_indent);
let indent = prev_indent + style.margin.left + style.padding.left;
let available_width = ctx.settings.content_width()
- prev_indent
- style.margin.left
- style.padding.left
- style.margin.right
- style.padding.right;
draw_box_border(ctx, style, content_start_y, indent, available_width);
ctx.consume_height(style.margin.bottom);
}
pub(crate) fn draw_box_background(
ctx: &mut PageContext,
style: &Style,
content_start_y: f32,
prev_indent: f32,
) {
if let Some(bg_color) = style.background_color {
let content_x = ctx.settings.content_x();
let content_y = ctx.settings.content_y();
let content_width = ctx.settings.content_width();
let bg_top = content_y + content_start_y - style.padding.top;
let bg_bottom = content_y + ctx.current_y + style.padding.bottom;
let bg_left = content_x + prev_indent + style.margin.left;
let bg_right = content_x + content_width - style.margin.right;
ctx.add_element_before_text(VisualElement::Rect {
rect: Rect::new(
bg_left as f64,
bg_top as f64,
bg_right as f64,
bg_bottom as f64,
),
style: FillStrokeStyle {
fill: Some(bg_color),
stroke: None,
},
});
}
}
pub(crate) fn draw_box_border(
ctx: &mut PageContext,
style: &Style,
content_start_y: f32,
indent: f32,
available_width: f32,
) {
if !style.border.is_any_visible() {
return;
}
let content_x = ctx.settings.content_x();
let content_y = ctx.settings.content_y();
let bw = style.border.max_width();
let border_color = style.border.top.color;
let box_x = content_x + indent - style.padding.left - bw;
let box_y = content_y + content_start_y - style.padding.top - bw;
let box_w = available_width + style.padding.left + style.padding.right + 2.0 * bw;
let box_h =
ctx.current_y - content_start_y + style.padding.top + style.padding.bottom + 2.0 * bw;
draw_border(
ctx,
box_x,
box_y,
box_w,
box_h,
border_color,
bw,
style.border.radius,
);
}
#[allow(clippy::too_many_arguments)]
fn draw_border(
ctx: &mut PageContext,
x: f32,
y: f32,
width: f32,
height: f32,
border_color: Color,
border_width: f32,
radius: f32,
) {
if radius > 0.0 {
let r = radius as f64;
ctx.add_element(VisualElement::RoundedRect {
rect: Rect::new(x as f64, y as f64, (x + width) as f64, (y + height) as f64),
radii: (r, r, r, r),
style: FillStrokeStyle {
fill: None,
stroke: Some(Stroke::new(border_color, border_width as f64)),
},
});
} else {
let x = x as f64;
let y = y as f64;
let w = width as f64;
let h = height as f64;
let bw = border_width as f64;
ctx.add_element(VisualElement::Rect {
rect: Rect::new(x, y, x + w, y + bw),
style: FillStrokeStyle {
fill: Some(border_color),
stroke: None,
},
});
ctx.add_element(VisualElement::Rect {
rect: Rect::new(x, y + h - bw, x + w, y + h),
style: FillStrokeStyle {
fill: Some(border_color),
stroke: None,
},
});
ctx.add_element(VisualElement::Rect {
rect: Rect::new(x, y, x + bw, y + h),
style: FillStrokeStyle {
fill: Some(border_color),
stroke: None,
},
});
ctx.add_element(VisualElement::Rect {
rect: Rect::new(x + w - bw, y, x + w, y + h),
style: FillStrokeStyle {
fill: Some(border_color),
stroke: None,
},
});
}
}