1use std::convert::From;
8
9use conrod_core::{self as conrod, position::Scalar as ConrodScalar, Positionable, Widget};
10use plotters_backend::{
11 text_anchor, BackendColor, BackendCoord, BackendStyle, BackendTextStyle, DrawingBackend,
12 DrawingErrorKind,
13};
14
15use crate::error::ConrodBackendError;
16use crate::graph::ConrodBackendReusableGraph;
17use crate::triangulate;
18use crate::utils::{color, convert, path, position, shape};
19
20pub struct ConrodBackend<'a, 'b> {
22 ui: &'a mut conrod::UiCell<'b>,
23 size: (u32, u32),
24 parent: conrod::widget::Id,
25 font: conrod::text::font::Id,
26 graph: &'a mut ConrodBackendReusableGraph,
27}
28
29impl<'a, 'b> ConrodBackend<'a, 'b> {
30 pub fn new(
37 ui: &'a mut conrod::UiCell<'b>,
38 size: (u32, u32),
39 parent: conrod::widget::Id,
40 font: conrod::text::font::Id,
41 graph: &'a mut ConrodBackendReusableGraph,
42 ) -> Self {
43 graph.prepare();
47
48 Self {
49 ui,
50 parent,
51 font,
52 size,
53 graph,
54 }
55 }
56}
57
58impl<'a, 'b> DrawingBackend for ConrodBackend<'a, 'b> {
59 type ErrorType = ConrodBackendError;
60
61 fn get_size(&self) -> (u32, u32) {
62 self.size
63 }
64
65 fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<ConrodBackendError>> {
66 Ok(())
67 }
68
69 fn present(&mut self) -> Result<(), DrawingErrorKind<ConrodBackendError>> {
70 Ok(())
71 }
72
73 fn draw_pixel(
74 &mut self,
75 _point: BackendCoord,
76 _color: BackendColor,
77 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
78 Ok(())
86 }
87
88 fn draw_line<S: BackendStyle>(
89 &mut self,
90 from: BackendCoord,
91 to: BackendCoord,
92 style: &S,
93 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
94 if let Some(position) = position::PositionParent::from(&self.ui, self.parent) {
96 let line_style = conrod::widget::primitive::line::Style::solid()
98 .color(color::Color::from(&style.color()).into())
99 .thickness(style.stroke_width() as ConrodScalar);
100
101 conrod::widget::line::Line::abs_styled(
103 position.abs_point_conrod_scalar(&from),
104 position.abs_point_conrod_scalar(&to),
105 line_style,
106 )
107 .top_left_of(self.parent)
108 .set(self.graph.line.next(&mut self.ui), &mut self.ui);
109
110 Ok(())
111 } else {
112 Err(DrawingErrorKind::DrawingError(
113 ConrodBackendError::NoParentPosition,
114 ))
115 }
116 }
117
118 fn draw_rect<S: BackendStyle>(
119 &mut self,
120 upper_left: BackendCoord,
121 bottom_right: BackendCoord,
122 style: &S,
123 fill: bool,
124 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
125 let rectangle_style = if fill {
127 conrod::widget::primitive::shape::Style::fill_with(
128 color::Color::from(&style.color()).into(),
129 )
130 } else {
131 conrod::widget::primitive::shape::Style::outline_styled(
132 conrod::widget::primitive::line::Style::new()
133 .color(color::Color::from(&style.color()).into())
134 .thickness(style.stroke_width() as ConrodScalar),
135 )
136 };
137
138 conrod::widget::rectangle::Rectangle::styled(
140 [
141 (bottom_right.0 - upper_left.0) as ConrodScalar,
142 (bottom_right.1 - upper_left.1) as ConrodScalar,
143 ],
144 rectangle_style,
145 )
146 .top_left_with_margins_on(
147 self.parent,
148 upper_left.1 as ConrodScalar,
149 upper_left.0 as ConrodScalar,
150 )
151 .set(self.graph.rect.next(&mut self.ui), &mut self.ui);
152
153 Ok(())
154 }
155
156 fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
157 &mut self,
158 path: I,
159 style: &S,
160 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
161 if let Some(position) = position::PositionParent::from(&self.ui, self.parent) {
163 let line_style = conrod::widget::primitive::line::Style::solid()
165 .color(color::Color::from(&style.color()).into())
166 .thickness(style.stroke_width() as ConrodScalar);
167
168 conrod::widget::point_path::PointPath::abs_styled(
170 path.into_iter()
171 .map(|point| position.abs_point_conrod_scalar(&point))
172 .collect::<Vec<conrod::position::Point>>(),
173 line_style,
174 )
175 .top_left_of(self.parent)
176 .set(self.graph.path.next(&mut self.ui), &mut self.ui);
177
178 Ok(())
179 } else {
180 Err(DrawingErrorKind::DrawingError(
181 ConrodBackendError::NoParentPosition,
182 ))
183 }
184 }
185
186 fn draw_circle<S: BackendStyle>(
187 &mut self,
188 center: BackendCoord,
189 radius: u32,
190 style: &S,
191 fill: bool,
192 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
193 let circle_style = if fill {
195 conrod::widget::primitive::shape::Style::fill_with(
196 color::Color::from(&style.color()).into(),
197 )
198 } else {
199 conrod::widget::primitive::shape::Style::outline_styled(
200 conrod::widget::primitive::line::Style::new()
201 .color(color::Color::from(&style.color()).into())
202 .thickness(style.stroke_width() as ConrodScalar),
203 )
204 };
205
206 conrod::widget::circle::Circle::styled(radius as ConrodScalar, circle_style)
208 .top_left_with_margins_on(
209 self.parent,
210 (center.1 - radius as i32) as ConrodScalar,
211 (center.0 - radius as i32) as ConrodScalar,
212 )
213 .set(self.graph.circle.next(&mut self.ui), &mut self.ui);
214
215 Ok(())
216 }
217
218 fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
219 &mut self,
220 vert: I,
221 style: &S,
222 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
223 if let Some(position) = position::PositionParent::from(&self.ui, self.parent) {
225 let simplified_path: Vec<_> = path::PathSimplifier::from(
229 vert.into_iter()
230 .map(|vertex| position.abs_point_path_simplifier(&vertex)),
231 )
232 .collect();
233
234 if let Ok(mut shape_splitter) = shape::ShapeSplitter::try_from(&simplified_path) {
238 let polygon_style = conrod::widget::primitive::shape::Style::fill_with(
240 color::Color::from(&style.color()).into(),
241 );
242
243 for shape_points in shape_splitter.collect() {
247 if shape_points.len() >= 3 {
249 let triangles = triangulate::triangulate_points(shape_points.iter());
250
251 for index in 0..triangles.size() {
252 conrod::widget::polygon::Polygon::abs_styled(
253 triangles.get_triangle(index).points.iter().copied(),
254 polygon_style,
255 )
256 .top_left_of(self.parent)
257 .set(self.graph.fill.next(&mut self.ui), &mut self.ui);
258 }
259 }
260 }
261 }
262
263 Ok(())
264 } else {
265 Err(DrawingErrorKind::DrawingError(
266 ConrodBackendError::NoParentPosition,
267 ))
268 }
269 }
270
271 fn draw_text<S: BackendTextStyle>(
272 &mut self,
273 text: &str,
274 style: &S,
275 pos: BackendCoord,
276 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
277 let (text_width_estimated, font_size_final) = convert::font_style(text, style.size());
279
280 let mut text_style = conrod::widget::primitive::text::Style::default();
282
283 text_style.color = Some(color::Color::from(&style.color()).into());
284 text_style.font_id = Some(Some(self.font));
285 text_style.font_size = Some(font_size_final);
286
287 text_style.justify = Some(match style.anchor().h_pos {
288 text_anchor::HPos::Left => conrod::text::Justify::Left,
289 text_anchor::HPos::Right => conrod::text::Justify::Right,
290 text_anchor::HPos::Center => conrod::text::Justify::Center,
291 });
292
293 conrod::widget::Text::new(text)
295 .with_style(text_style)
296 .top_left_with_margins_on(
297 self.parent,
298 pos.1 as ConrodScalar - (style.size() / 2.0 + 1.0),
299 pos.0 as ConrodScalar - text_width_estimated,
300 )
301 .set(self.graph.text.next(&mut self.ui), &mut self.ui);
302
303 Ok(())
304 }
305
306 fn estimate_text_size<S: BackendTextStyle>(
307 &self,
308 text: &str,
309 style: &S,
310 ) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
311 let (text_width_estimated, text_height_estimated) = convert::font_style(text, style.size());
312
313 Ok((text_width_estimated as u32, text_height_estimated))
315 }
316
317 fn blit_bitmap(
318 &mut self,
319 _pos: BackendCoord,
320 (_iw, _ih): (u32, u32),
321 _src: &[u8],
322 ) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
323 Ok(())
330 }
331}