monorepo/dashboard/src/ui/pie_chart.rs

142 lines
3.9 KiB
Rust

use chrono::{Duration, NaiveTime};
use glib::Object;
use gtk::{prelude::*, subclass::prelude::*};
use std::{cell::RefCell, f64::consts::PI, rc::Rc};
#[derive(Clone, Debug)]
pub struct Color {
pub r: f64,
pub g: f64,
pub b: f64,
}
#[derive(Clone, Debug)]
pub struct Wedge {
pub start_angle: f64,
pub end_angle: f64,
pub color: Color,
}
#[derive(Default)]
pub struct PieChartPrivate {
rotation: Rc<RefCell<f64>>,
wedges: Rc<RefCell<Vec<Wedge>>>,
}
#[glib::object_subclass]
impl ObjectSubclass for PieChartPrivate {
const NAME: &'static str = "PieChart";
type Type = PieChart;
type ParentType = gtk::DrawingArea;
}
impl ObjectImpl for PieChartPrivate {}
impl WidgetImpl for PieChartPrivate {}
impl DrawingAreaImpl for PieChartPrivate {}
glib::wrapper! {
pub struct PieChart(ObjectSubclass<PieChartPrivate>) @extends gtk::DrawingArea, gtk::Widget;
}
impl PieChart {
pub fn new(builder: PieChartBuilder) -> Self {
let s: Self = Object::builder().build();
s.set_content_width(500);
s.set_content_height(500);
*s.imp().rotation.borrow_mut() = builder.rotation;
*s.imp().wedges.borrow_mut() = builder.wedges;
s.set_draw_func({
let s = s.clone();
move |_, context, width, height| {
println!("redrawing: {} {}", width, height);
let radius = width.min(height) as f64 / 2. * 0.9;
let center_x = (width / 2) as f64;
let center_y = (height / 2) as f64;
let rotation = s.imp().rotation.borrow().clone();
let wedges = s.imp().wedges.borrow().clone();
context.set_source_rgba(0., 0., 0., 0.);
let _ = context.paint();
context.set_line_width(2.);
wedges.iter().for_each(
|Wedge {
start_angle,
end_angle,
color,
}| {
println!(
"wedge: {:.02?} {:.02?} {:.02?}",
start_angle, end_angle, color
);
println!(
"wedge: {:.02?} {:.02?} [{:.02?}]",
start_angle + rotation,
end_angle + rotation,
rotation
);
context.move_to(center_x, center_y);
context.set_source_rgb(color.r, color.g, color.b);
context.arc(
center_x,
center_y,
radius,
start_angle + rotation,
end_angle + rotation,
);
let _ = context.fill();
},
);
context.set_source_rgb(1., 1., 1.);
context.arc(center_x, center_y, radius, 0., 2. * PI);
let _ = context.stroke();
}
});
s
}
pub fn set_rotation(&mut self, rotation: f64) {
*self.imp().rotation.borrow_mut() = rotation;
self.queue_draw();
}
pub fn add_wedge(&mut self, wedge: Wedge) {
(*self.imp().wedges.borrow_mut()).push(wedge);
self.queue_draw();
}
pub fn builder() -> PieChartBuilder {
PieChartBuilder {
rotation: 0.,
wedges: vec![],
}
}
}
pub struct PieChartBuilder {
rotation: f64,
wedges: Vec<Wedge>,
}
impl PieChartBuilder {
pub fn rotation(mut self, rotation: f64) -> Self {
self.rotation = rotation;
self
}
pub fn wedges(mut self, wedges: Vec<Wedge>) -> Self {
self.wedges = wedges;
self
}
pub fn build(self) -> PieChart {
PieChart::new(self)
}
}