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) } }