nannou/draw/properties/stroke.rs
1use lyon::tessellation::{LineCap, LineJoin, StrokeOptions};
2
3/// Nodes that support stroke tessellation.
4///
5/// This trait allows the `Drawing` context to automatically provide an implementation of the
6/// following builder methods for all primitives that provide some stroke tessellation options.
7pub trait SetStroke: Sized {
8 /// Provide a mutable reference to the `StrokeOptions` field.
9 fn stroke_options_mut(&mut self) -> &mut StrokeOptions;
10
11 /// Specify the whole set of stroke tessellation options.
12 fn stroke_opts(mut self, opts: StrokeOptions) -> Self {
13 *self.stroke_options_mut() = opts;
14 self
15 }
16
17 /// The start line cap as specified by the SVG spec.
18 fn start_cap(mut self, cap: LineCap) -> Self {
19 self.stroke_options_mut().start_cap = cap;
20 self
21 }
22
23 /// The end line cap as specified by the SVG spec.
24 fn end_cap(mut self, cap: LineCap) -> Self {
25 self.stroke_options_mut().end_cap = cap;
26 self
27 }
28
29 /// The start and end line cap as specified by the SVG spec.
30 fn caps(self, cap: LineCap) -> Self {
31 self.start_cap(cap).end_cap(cap)
32 }
33
34 /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
35 /// sub-path will therefore not have any stroke.
36 fn start_cap_butt(self) -> Self {
37 self.start_cap(LineCap::Butt)
38 }
39
40 /// At the end of each sub-path, the shape representing the stroke will be extended by a
41 /// rectangle with the same width as the stroke width and whose length is half of the stroke
42 /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
43 /// sub-path consists solely of a square with side length equal to the stroke width, centered
44 /// at the sub-path's point.
45 fn start_cap_square(self) -> Self {
46 self.start_cap(LineCap::Square)
47 }
48
49 /// At each end of each sub-path, the shape representing the stroke will be extended by a half
50 /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
51 /// resulting effect is that the stroke for that sub-path consists solely of a full circle
52 /// centered at the sub-path's point.
53 fn start_cap_round(self) -> Self {
54 self.start_cap(LineCap::Round)
55 }
56
57 /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
58 /// sub-path will therefore not have any stroke.
59 fn end_cap_butt(self) -> Self {
60 self.end_cap(LineCap::Butt)
61 }
62
63 /// At the end of each sub-path, the shape representing the stroke will be extended by a
64 /// rectangle with the same width as the stroke width and whose length is half of the stroke
65 /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
66 /// sub-path consists solely of a square with side length equal to the stroke width, centered
67 /// at the sub-path's point.
68 fn end_cap_square(self) -> Self {
69 self.end_cap(LineCap::Square)
70 }
71
72 /// At each end of each sub-path, the shape representing the stroke will be extended by a half
73 /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
74 /// resulting effect is that the stroke for that sub-path consists solely of a full circle
75 /// centered at the sub-path's point.
76 fn end_cap_round(self) -> Self {
77 self.end_cap(LineCap::Round)
78 }
79
80 /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
81 /// sub-path will therefore not have any stroke.
82 fn caps_butt(self) -> Self {
83 self.caps(LineCap::Butt)
84 }
85
86 /// At the end of each sub-path, the shape representing the stroke will be extended by a
87 /// rectangle with the same width as the stroke width and whose length is half of the stroke
88 /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
89 /// sub-path consists solely of a square with side length equal to the stroke width, centered
90 /// at the sub-path's point.
91 fn caps_square(self) -> Self {
92 self.caps(LineCap::Square)
93 }
94
95 /// At each end of each sub-path, the shape representing the stroke will be extended by a half
96 /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
97 /// resulting effect is that the stroke for that sub-path consists solely of a full circle
98 /// centered at the sub-path's point.
99 fn caps_round(self) -> Self {
100 self.caps(LineCap::Round)
101 }
102
103 /// The way in which lines are joined at the vertices, matching the SVG spec.
104 ///
105 /// Default value is `MiterClip`.
106 fn join(mut self, join: LineJoin) -> Self {
107 self.stroke_options_mut().line_join = join;
108 self
109 }
110
111 /// A sharp corner is to be used to join path segments.
112 fn join_miter(self) -> Self {
113 self.join(LineJoin::Miter)
114 }
115
116 /// Same as a `join_miter`, but if the miter limit is exceeded, the miter is clipped at a miter
117 /// length equal to the miter limit value multiplied by the stroke width.
118 fn join_miter_clip(self) -> Self {
119 self.join(LineJoin::MiterClip)
120 }
121
122 /// A round corner is to be used to join path segments.
123 fn join_round(self) -> Self {
124 self.join(LineJoin::Round)
125 }
126
127 /// A bevelled corner is to be used to join path segments. The bevel shape is a triangle that
128 /// fills the area between the two stroked segments.
129 fn join_bevel(self) -> Self {
130 self.join(LineJoin::Bevel)
131 }
132
133 /// The total stroke_weight (aka width) of the line.
134 fn stroke_weight(mut self, stroke_weight: f32) -> Self {
135 self.stroke_options_mut().line_width = stroke_weight;
136 self
137 }
138
139 /// Describes the limit before miter lines will clip, as described in the SVG spec.
140 ///
141 /// Must be greater than or equal to `1.0`.
142 fn miter_limit(mut self, limit: f32) -> Self {
143 self.stroke_options_mut().miter_limit = limit;
144 self
145 }
146
147 /// Maximum allowed distance to the path when building an approximation.
148 fn stroke_tolerance(mut self, tolerance: f32) -> Self {
149 self.stroke_options_mut().tolerance = tolerance;
150 self
151 }
152}
153
154impl SetStroke for Option<StrokeOptions> {
155 fn stroke_options_mut(&mut self) -> &mut StrokeOptions {
156 self.get_or_insert_with(Default::default)
157 }
158}