1use std::marker::PhantomData;
2
3use super::context::ChartContext;
4use crate::coord::{MeshLine, Ranged, RangedCoord};
5use crate::drawing::backend::DrawingBackend;
6use crate::drawing::DrawingAreaErrorKind;
7use crate::style::{FontDesc, Mixable, RGBColor, ShapeStyle, TextStyle};
8
9pub struct MeshStyle<'a, X: Ranged, Y: Ranged, DB>
11where
12 DB: DrawingBackend,
13{
14 pub(super) draw_x_mesh: bool,
15 pub(super) draw_y_mesh: bool,
16 pub(super) draw_x_axis: bool,
17 pub(super) draw_y_axis: bool,
18 pub(super) x_label_offset: i32,
19 pub(super) n_x_labels: usize,
20 pub(super) n_y_labels: usize,
21 pub(super) axis_desc_style: Option<TextStyle<'a>>,
22 pub(super) x_desc: Option<String>,
23 pub(super) y_desc: Option<String>,
24 pub(super) line_style_1: Option<ShapeStyle<'a>>,
25 pub(super) line_style_2: Option<ShapeStyle<'a>>,
26 pub(super) axis_style: Option<ShapeStyle<'a>>,
27 pub(super) label_style: Option<TextStyle<'a>>,
28 pub(super) format_x: &'a dyn Fn(&X::ValueType) -> String,
29 pub(super) format_y: &'a dyn Fn(&Y::ValueType) -> String,
30 pub(super) target: Option<&'a mut ChartContext<DB, RangedCoord<X, Y>>>,
31 pub(super) _pahtom_data: PhantomData<(X, Y)>,
32}
33
34impl<'a, X, Y, DB> MeshStyle<'a, X, Y, DB>
35where
36 X: Ranged,
37 Y: Ranged,
38 DB: DrawingBackend,
39{
40 pub fn x_label_offset(&mut self, value: i32) -> &mut Self {
44 self.x_label_offset = value;
45 self
46 }
47
48 pub fn disable_x_mesh(&mut self) -> &mut Self {
50 self.draw_x_mesh = false;
51 self
52 }
53
54 pub fn disable_y_mesh(&mut self) -> &mut Self {
56 self.draw_y_mesh = false;
57 self
58 }
59
60 pub fn disable_x_axis(&mut self) -> &mut Self {
62 self.draw_x_axis = false;
63 self
64 }
65
66 pub fn disable_y_axis(&mut self) -> &mut Self {
68 self.draw_y_axis = false;
69 self
70 }
71
72 pub fn axis_style<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
75 self.axis_style = Some(style.into());
76 self
77 }
78 pub fn x_labels(&mut self, value: usize) -> &mut Self {
81 self.n_x_labels = value;
82 self
83 }
84
85 pub fn y_labels(&mut self, value: usize) -> &mut Self {
88 self.n_y_labels = value;
89 self
90 }
91
92 pub fn line_style_1<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
95 self.line_style_1 = Some(style.into());
96 self
97 }
98
99 pub fn line_style_2<T: Into<ShapeStyle<'a>>>(&mut self, style: T) -> &mut Self {
102 self.line_style_2 = Some(style.into());
103 self
104 }
105
106 pub fn label_style<T: Into<TextStyle<'a>>>(&mut self, style: T) -> &mut Self {
109 self.label_style = Some(style.into());
110 self
111 }
112
113 pub fn x_label_formatter(&mut self, fmt: &'a dyn Fn(&X::ValueType) -> String) -> &mut Self {
116 self.format_x = fmt;
117 self
118 }
119
120 pub fn y_label_formatter(&mut self, fmt: &'a dyn Fn(&Y::ValueType) -> String) -> &mut Self {
123 self.format_y = fmt;
124 self
125 }
126
127 pub fn axis_desc_style<T: Into<TextStyle<'a>>>(&mut self, style: T) -> &mut Self {
130 self.axis_desc_style = Some(style.into());
131 self
132 }
133
134 pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
137 self.x_desc = Some(desc.into());
138 self
139 }
140
141 pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
144 self.y_desc = Some(desc.into());
145 self
146 }
147
148 pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
150 let mut target = None;
151 std::mem::swap(&mut target, &mut self.target);
152 let target = target.unwrap();
153
154 let default_mesh_color_1 = RGBColor(0, 0, 0).mix(0.2);
155 let default_mesh_color_2 = RGBColor(0, 0, 0).mix(0.1);
156 let default_axis_color = RGBColor(0, 0, 0);
157 let default_label_font = FontDesc::new("Arial", 12.0);
158
159 let mesh_style_1 = self
160 .line_style_1
161 .clone()
162 .unwrap_or_else(|| (&default_mesh_color_1).into());
163 let mesh_style_2 = self
164 .line_style_2
165 .clone()
166 .unwrap_or_else(|| (&default_mesh_color_2).into());
167 let axis_style = self
168 .axis_style
169 .clone()
170 .unwrap_or_else(|| (&default_axis_color).into());
171
172 let label_style =
173 unsafe { std::mem::transmute::<_, Option<TextStyle>>(self.label_style.clone()) }
174 .unwrap_or_else(|| (&default_label_font).into());
175
176 let axis_desc_style =
177 unsafe { std::mem::transmute::<_, Option<TextStyle>>(self.axis_desc_style.clone()) }
178 .unwrap_or_else(|| label_style.clone());
179
180 target.draw_mesh(
181 (self.n_y_labels * 10, self.n_x_labels * 10),
182 &mesh_style_2,
183 &label_style,
184 |_| None,
185 self.draw_x_mesh,
186 self.draw_y_mesh,
187 self.x_label_offset,
188 false,
189 false,
190 &axis_style,
191 &axis_desc_style,
192 self.x_desc.clone(),
193 self.y_desc.clone(),
194 )?;
195
196 target.draw_mesh(
197 (self.n_y_labels, self.n_x_labels),
198 &mesh_style_1,
199 &label_style,
200 |m| match m {
201 MeshLine::XMesh(_, _, v) => Some((self.format_x)(v)),
202 MeshLine::YMesh(_, _, v) => Some((self.format_y)(v)),
203 },
204 self.draw_x_mesh,
205 self.draw_y_mesh,
206 self.x_label_offset,
207 self.draw_x_axis,
208 self.draw_y_axis,
209 &axis_style,
210 &axis_desc_style,
211 None,
212 None,
213 )
214 }
215}