plotters_ratatui_backend/
widget.rs1use plotters::coord;
2use plotters::prelude::{DrawingArea, DrawingAreaErrorKind, IntoDrawingArea};
3use ratatui::layout;
4use ratatui::prelude::Buffer;
5use ratatui::widgets::canvas::Canvas;
6use ratatui::widgets::Widget;
7
8use crate::{Error, RatatuiBackend};
9
10pub type AreaResult<T = ()> = Result<T, DrawingAreaErrorKind<Error>>;
11
12pub struct PlottersWidget<D, E> {
14 pub draw: D,
15 pub error_handler: E,
16}
17
18pub fn widget_fn(
20 draw_fn: impl Fn(DrawingArea<RatatuiBackend, coord::Shift>) -> AreaResult,
21) -> PlottersWidget<impl Draw, impl Fn(DrawingAreaErrorKind<Error>)> {
22 PlottersWidget {
23 draw: DrawFn(draw_fn),
24 error_handler: |err| log::error!("Plotters draw error: {err:?}"),
25 }
26}
27
28pub struct DrawFn<F>(pub F);
29
30impl<F: Fn(DrawingArea<RatatuiBackend, coord::Shift>) -> AreaResult> Draw for DrawFn<F> {
31 fn draw(&self, b: DrawingArea<RatatuiBackend, coord::Shift>) -> AreaResult { (self.0)(b) }
32}
33
34pub trait Draw {
35 fn draw(&self, b: DrawingArea<RatatuiBackend, coord::Shift>) -> AreaResult;
36}
37
38impl<D: Draw, E: Fn(DrawingAreaErrorKind<Error>)> Widget for PlottersWidget<D, E> {
39 fn render(self, area: layout::Rect, buf: &mut Buffer) {
40 let (size_x, size_y) = super::rect_to_size(area);
41 log::debug!("size: {area:?}, {size_x}, {size_y}");
42 let canvas =
43 Canvas::default().x_bounds([0.0, 1.0]).y_bounds([0.0, 1.0]).paint(move |canvas| {
44 let backend = RatatuiBackend { canvas, size: area };
45 let area = backend.into_drawing_area();
46 if let Err(err) = self.draw.draw(area) {
47 (self.error_handler)(err);
48 }
49 });
50 canvas.render(area, buf)
51 }
52}