use super::super::draw_command::DrawCommand;
use super::super::BoxConstraints;
use super::line_emit::resolve_line_height;
use super::types::ParagraphStyle;
use crate::render::dimension::Pt;
use crate::render::geometry::PtOffset;
#[derive(Clone, Copy)]
pub(super) enum SegmentEdges {
Whole,
First,
Middle,
Last,
}
impl SegmentEdges {
pub(super) fn for_segment(is_first: bool, is_last: bool) -> Self {
match (is_first, is_last) {
(true, true) => Self::Whole,
(true, false) => Self::First,
(false, false) => Self::Middle,
(false, true) => Self::Last,
}
}
fn draw_top(self) -> bool {
matches!(self, Self::Whole | Self::First)
}
fn draw_bottom(self) -> bool {
matches!(self, Self::Whole | Self::Last)
}
}
pub(super) fn emit_paragraph_borders_and_shading(
commands: &mut Vec<DrawCommand>,
style: &ParagraphStyle,
constraints: &BoxConstraints,
cursor_y: Pt,
default_line_height: Pt,
no_lines: bool,
) -> Pt {
emit_segment_borders_and_shading(
commands,
style,
constraints,
cursor_y,
default_line_height,
no_lines,
SegmentEdges::Whole,
)
}
pub(super) fn emit_segment_borders_and_shading(
commands: &mut Vec<DrawCommand>,
style: &ParagraphStyle,
constraints: &BoxConstraints,
content_bottom: Pt,
default_line_height: Pt,
no_lines: bool,
edges: SegmentEdges,
) -> Pt {
let draw_top = edges.draw_top();
let draw_bottom = edges.draw_bottom();
let border_space_top = style
.borders
.as_ref()
.and_then(|b| b.top.as_ref())
.map(|b| b.space)
.unwrap_or(Pt::ZERO);
let border_space_bottom = style
.borders
.as_ref()
.and_then(|b| b.bottom.as_ref())
.map(|b| b.space)
.unwrap_or(Pt::ZERO);
let para_left = style.indent_left;
let para_right = constraints.max_width - style.indent_right;
let box_top = if draw_top {
style.space_before - border_space_top
} else {
Pt::ZERO
};
let box_bottom = if draw_bottom {
content_bottom + border_space_bottom
} else {
content_bottom
};
if let Some(bg_color) = style.shading {
commands.insert(
0,
DrawCommand::Rect {
rect: crate::render::geometry::PtRect::from_xywh(
para_left,
box_top,
para_right - para_left,
box_bottom - box_top,
),
color: bg_color,
},
);
}
if let Some(ref borders) = style.borders {
if draw_top {
if let Some(ref top) = borders.top {
commands.push(DrawCommand::Line {
line: crate::render::geometry::PtLineSegment::new(
PtOffset::new(para_left, box_top),
PtOffset::new(para_right, box_top),
),
color: top.color,
width: top.width,
});
}
}
if draw_bottom {
if let Some(ref bottom) = borders.bottom {
commands.push(DrawCommand::Line {
line: crate::render::geometry::PtLineSegment::new(
PtOffset::new(para_left, box_bottom),
PtOffset::new(para_right, box_bottom),
),
color: bottom.color,
width: bottom.width,
});
}
}
if let Some(ref left) = borders.left {
commands.push(DrawCommand::Line {
line: crate::render::geometry::PtLineSegment::new(
PtOffset::new(para_left, box_top),
PtOffset::new(para_left, box_bottom),
),
color: left.color,
width: left.width,
});
}
if let Some(ref right) = borders.right {
commands.push(DrawCommand::Line {
line: crate::render::geometry::PtLineSegment::new(
PtOffset::new(para_right, box_top),
PtOffset::new(para_right, box_bottom),
),
color: right.color,
width: right.width,
});
}
}
let mut cursor_y = content_bottom;
if draw_bottom {
cursor_y = content_bottom + border_space_bottom + style.space_after;
}
if no_lines {
let line_h = resolve_line_height(
default_line_height,
default_line_height,
&style.line_spacing,
);
cursor_y = style.space_before + line_h + style.space_after;
}
cursor_y
}