laser_pdf/elements/
line.rs1use crate::{utils::*, *};
2
3pub struct Line {
8 pub style: LineStyle,
10}
11
12impl Line {
13 pub fn new(thickness: f32) -> Self {
14 Line {
15 style: LineStyle {
16 thickness,
17 color: 0x00_00_00_FF,
18 dash_pattern: None,
19 cap_style: LineCapStyle::Butt,
20 },
21 }
22 }
23}
24
25impl Element for Line {
26 fn measure(&self, mut ctx: MeasureCtx) -> ElementSize {
27 ctx.break_if_appropriate_for_min_height(self.style.thickness);
28
29 size(self, ctx.width)
30 }
31
32 fn draw(&self, mut ctx: DrawCtx) -> ElementSize {
33 ctx.break_if_appropriate_for_min_height(self.style.thickness);
34
35 if ctx.width.expand {
36 let (color, _alpha) = u32_to_color_and_alpha(self.style.color);
37 let style = self.style;
38
39 let layer = ctx.location.layer(ctx.pdf);
40
41 layer
42 .save_state()
43 .set_line_width(mm_to_pt(style.thickness))
44 .set_stroke_rgb(color[0], color[1], color[2])
45 .set_line_cap(style.cap_style.into());
46
47 if let Some(pattern) = style.dash_pattern {
48 layer.set_dash_pattern(pattern.dashes.map(f32::from), pattern.offset as f32);
49 }
50
51 let line_y = ctx.location.pos.1 - self.style.thickness / 2.0;
52
53 layer
54 .move_to(mm_to_pt(ctx.location.pos.0), mm_to_pt(line_y))
55 .line_to(
56 mm_to_pt(ctx.location.pos.0 + ctx.width.max),
57 mm_to_pt(line_y),
58 )
59 .stroke()
60 .restore_state();
61 }
62
63 size(self, ctx.width)
64 }
65}
66
67fn size(line: &Line, width: WidthConstraint) -> ElementSize {
68 ElementSize {
69 width: Some(width.constrain(0.)),
70 height: Some(line.style.thickness),
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::test_utils::*;
78
79 #[test]
80 fn test_line() {
81 for output in (ElementTestParams {
82 first_height: 0.2,
83 ..Default::default()
84 })
85 .run(&Line {
86 style: LineStyle {
87 thickness: 1.,
88 color: 0,
89 dash_pattern: None,
90 cap_style: LineCapStyle::Butt,
91 },
92 }) {
93 output.assert_size(ElementSize {
94 width: Some(output.width.constrain(0.)),
95 height: Some(1.),
96 });
97
98 if let Some(b) = output.breakable {
99 if output.first_height == 0.2 {
100 b.assert_break_count(1);
101 } else {
102 b.assert_break_count(0);
103 }
104
105 b.assert_extra_location_min_height(None);
106 }
107 }
108 }
109}