use std::marker::PhantomData;
use super::context::ChartContext;
use crate::coord::{MeshLine, Ranged, RangedCoord};
use crate::drawing::backend::DrawingBackend;
use crate::drawing::DrawingAreaErrorKind;
use crate::style::{Color, FontDesc, RGBColor, ShapeStyle, TextStyle};
pub struct MeshStyle<'a, 'b, X: Ranged, Y: Ranged, DB>
where
DB: DrawingBackend,
{
pub(super) draw_x_mesh: bool,
pub(super) draw_y_mesh: bool,
pub(super) draw_x_axis: bool,
pub(super) draw_y_axis: bool,
pub(super) x_label_offset: i32,
pub(super) n_x_labels: usize,
pub(super) n_y_labels: usize,
pub(super) axis_desc_style: Option<TextStyle<'b>>,
pub(super) x_desc: Option<String>,
pub(super) y_desc: Option<String>,
pub(super) line_style_1: Option<ShapeStyle>,
pub(super) line_style_2: Option<ShapeStyle>,
pub(super) axis_style: Option<ShapeStyle>,
pub(super) label_style: Option<TextStyle<'b>>,
pub(super) format_x: &'b dyn Fn(&X::ValueType) -> String,
pub(super) format_y: &'b dyn Fn(&Y::ValueType) -> String,
pub(super) target: Option<&'b mut ChartContext<'a, DB, RangedCoord<X, Y>>>,
pub(super) _pahtom_data: PhantomData<(X, Y)>,
}
impl<'a, 'b, X, Y, DB> MeshStyle<'a, 'b, X, Y, DB>
where
X: Ranged,
Y: Ranged,
DB: DrawingBackend,
{
pub fn x_label_offset(&mut self, value: i32) -> &mut Self {
self.x_label_offset = value;
self
}
pub fn disable_x_mesh(&mut self) -> &mut Self {
self.draw_x_mesh = false;
self
}
pub fn disable_y_mesh(&mut self) -> &mut Self {
self.draw_y_mesh = false;
self
}
pub fn disable_x_axis(&mut self) -> &mut Self {
self.draw_x_axis = false;
self
}
pub fn disable_y_axis(&mut self) -> &mut Self {
self.draw_y_axis = false;
self
}
pub fn axis_style<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
self.axis_style = Some(style.into());
self
}
pub fn x_labels(&mut self, value: usize) -> &mut Self {
self.n_x_labels = value;
self
}
pub fn y_labels(&mut self, value: usize) -> &mut Self {
self.n_y_labels = value;
self
}
pub fn line_style_1<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
self.line_style_1 = Some(style.into());
self
}
pub fn line_style_2<T: Into<ShapeStyle>>(&mut self, style: T) -> &mut Self {
self.line_style_2 = Some(style.into());
self
}
pub fn label_style<T: Into<TextStyle<'b>>>(&mut self, style: T) -> &mut Self {
self.label_style = Some(style.into());
self
}
pub fn x_label_formatter(&mut self, fmt: &'b dyn Fn(&X::ValueType) -> String) -> &mut Self {
self.format_x = fmt;
self
}
pub fn y_label_formatter(&mut self, fmt: &'b dyn Fn(&Y::ValueType) -> String) -> &mut Self {
self.format_y = fmt;
self
}
pub fn axis_desc_style<T: Into<TextStyle<'b>>>(&mut self, style: T) -> &mut Self {
self.axis_desc_style = Some(style.into());
self
}
pub fn x_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
self.x_desc = Some(desc.into());
self
}
pub fn y_desc<T: Into<String>>(&mut self, desc: T) -> &mut Self {
self.y_desc = Some(desc.into());
self
}
pub fn draw(&mut self) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
let mut target = None;
std::mem::swap(&mut target, &mut self.target);
let target = target.unwrap();
let default_mesh_color_1 = RGBColor(0, 0, 0).mix(0.2);
let default_mesh_color_2 = RGBColor(0, 0, 0).mix(0.1);
let default_axis_color = RGBColor(0, 0, 0);
let default_label_font = FontDesc::new("Arial", 12.0);
let mesh_style_1 = self
.line_style_1
.clone()
.unwrap_or_else(|| (&default_mesh_color_1).into());
let mesh_style_2 = self
.line_style_2
.clone()
.unwrap_or_else(|| (&default_mesh_color_2).into());
let axis_style = self
.axis_style
.clone()
.unwrap_or_else(|| (&default_axis_color).into());
let label_style = self
.label_style
.clone()
.unwrap_or_else(|| default_label_font.into());
let axis_desc_style = self
.axis_desc_style
.clone()
.unwrap_or_else(|| label_style.clone());
target.draw_mesh(
(self.n_y_labels * 10, self.n_x_labels * 10),
&mesh_style_2,
&label_style,
|_| None,
self.draw_x_mesh,
self.draw_y_mesh,
self.x_label_offset,
false,
false,
&axis_style,
&axis_desc_style,
self.x_desc.clone(),
self.y_desc.clone(),
)?;
target.draw_mesh(
(self.n_y_labels, self.n_x_labels),
&mesh_style_1,
&label_style,
|m| match m {
MeshLine::XMesh(_, _, v) => Some((self.format_x)(v)),
MeshLine::YMesh(_, _, v) => Some((self.format_y)(v)),
},
self.draw_x_mesh,
self.draw_y_mesh,
self.x_label_offset,
self.draw_x_axis,
self.draw_y_axis,
&axis_style,
&axis_desc_style,
None,
None,
)
}
}