From 28192ff8d7052fd0eac4f687e31cf1010b4cd69f Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Wed, 9 Aug 2023 10:54:27 -0400 Subject: [PATCH] Convert the pie chart to a drawing tool instead of a full widget --- dashboard/src/{ui => drawing}/mod.rs | 0 dashboard/src/drawing/pie_chart.rs | 100 +++++++++++++++++++ dashboard/src/main.rs | 76 +++++++++------ dashboard/src/ui/pie_chart.rs | 141 --------------------------- 4 files changed, 147 insertions(+), 170 deletions(-) rename dashboard/src/{ui => drawing}/mod.rs (100%) create mode 100644 dashboard/src/drawing/pie_chart.rs delete mode 100644 dashboard/src/ui/pie_chart.rs diff --git a/dashboard/src/ui/mod.rs b/dashboard/src/drawing/mod.rs similarity index 100% rename from dashboard/src/ui/mod.rs rename to dashboard/src/drawing/mod.rs diff --git a/dashboard/src/drawing/pie_chart.rs b/dashboard/src/drawing/pie_chart.rs new file mode 100644 index 0000000..8b9e97a --- /dev/null +++ b/dashboard/src/drawing/pie_chart.rs @@ -0,0 +1,100 @@ +use cairo::{Context, Format, ImageSurface}; +use std::f64::consts::PI; + +#[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, +} + +pub struct PieChart { + rotation: f64, + wedges: Vec, + width: i32, + height: i32, +} + +impl PieChart { + pub fn new() -> Self { + Self { + rotation: 0., + wedges: vec![], + width: 0, + height: 0, + } + } + + pub fn rotation(mut self, rotation: f64) -> Self { + self.rotation = rotation; + self + } + + pub fn wedges(mut self, wedge: impl Iterator) -> Self { + let mut wedges: Vec = wedge.collect(); + self.wedges.append(&mut wedges); + self + } + + pub fn width(mut self, width: i32) -> Self { + self.width = width; + self + } + + pub fn height(mut self, height: i32) -> Self { + self.height = height; + self + } + + pub fn draw(self, context: &Context) { + println!("drawing: {} {}", self.width, self.height); + let radius = self.width.min(self.height) as f64 / 2. * 0.9; + let center_x = (self.width / 2) as f64; + let center_y = (self.height / 2) as f64; + + context.set_source_rgba(0., 0., 0., 0.); + let _ = context.paint(); + + context.set_line_width(2.); + + self.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 + self.rotation, + end_angle + self.rotation, + self.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 + self.rotation, + end_angle + self.rotation, + ); + let _ = context.fill(); + }, + ); + + context.set_source_rgb(1., 1., 1.); + context.arc(center_x, center_y, radius, 0., 2. * PI); + let _ = context.stroke(); + } +} diff --git a/dashboard/src/main.rs b/dashboard/src/main.rs index ef4316b..111feb8 100644 --- a/dashboard/src/main.rs +++ b/dashboard/src/main.rs @@ -11,8 +11,8 @@ use gtk::{prelude::*, subclass::prelude::*, Orientation}; use ifc::IFC; use std::{cell::RefCell, env, f64::consts::PI, ops::Deref, rc::Rc}; -mod ui; -use ui::{Color, PieChart, Wedge}; +mod drawing; +use drawing::{Color, PieChart, Wedge}; /* use geo_types::{Latitude, Longitude}; @@ -214,14 +214,12 @@ impl Date { pub struct TransitClockPrivate { info: Rc>>, - chart: Rc>, } impl Default for TransitClockPrivate { fn default() -> Self { Self { info: Rc::new(RefCell::new(None)), - chart: Rc::new(RefCell::new(PieChart::builder().rotation(-PI / 2.).build())), } } } @@ -230,15 +228,15 @@ impl Default for TransitClockPrivate { impl ObjectSubclass for TransitClockPrivate { const NAME: &'static str = "TransitClock"; type Type = TransitClock; - type ParentType = gtk::Box; + type ParentType = gtk::DrawingArea; } impl ObjectImpl for TransitClockPrivate {} impl WidgetImpl for TransitClockPrivate {} -impl BoxImpl for TransitClockPrivate {} +impl DrawingAreaImpl for TransitClockPrivate {} glib::wrapper! { - pub struct TransitClock(ObjectSubclass) @extends gtk::Box, gtk::Widget; + pub struct TransitClock(ObjectSubclass) @extends gtk::DrawingArea, gtk::Widget; } impl TransitClock { @@ -247,30 +245,50 @@ impl TransitClock { s.set_width_request(500); s.set_height_request(500); - { - let mut chart = s.imp().chart.borrow_mut(); - s.append(&*chart); - { - let full_day = Duration::days(1).num_seconds() as f64; - let sunrise = sun_moon_info.sunrise - NaiveTime::from_hms_opt(0, 0, 0).unwrap(); - let sunset = sun_moon_info.sunset - NaiveTime::from_hms_opt(0, 0, 0).unwrap(); - - println!("{:?} -> {:?}", sunrise, sunset); - - chart.add_wedge(Wedge { - start_angle: (PI * 2.) * sunset.num_seconds() as f64 / full_day, - end_angle: (PI * 2.) * sunrise.num_seconds() as f64 / full_day, - color: Color { - r: 0.1, - g: 0.1, - b: 0.8, - }, - }); - } - } - *s.imp().info.borrow_mut() = Some(sun_moon_info); + s.set_draw_func({ + let s = s.clone(); + move |_, context, width, height| { + let center_x = width as f64 / 2.; + let center_y = height as f64 / 2.; + let radius = width.min(height) as f64 / 2.; + if let Some(ref info) = *s.imp().info.borrow() { + let full_day = Duration::days(1).num_seconds() as f64; + let sunrise = info.sunrise - NaiveTime::from_hms_opt(0, 0, 0).unwrap(); + let sunset = info.sunset - NaiveTime::from_hms_opt(0, 0, 0).unwrap(); + + PieChart::new() + .width(width) + .height(height) + .rotation(-PI / 2.) + .wedges( + vec![Wedge { + start_angle: (PI * 2.) * sunset.num_seconds() as f64 / full_day, + end_angle: (PI * 2.) * sunrise.num_seconds() as f64 / full_day, + color: Color { + r: 0.1, + g: 0.1, + b: 0.8, + }, + }] + .into_iter(), + ) + .draw(context); + + (0..24).for_each(|tick| { + context.set_source_rgb(0., 0., 0.); + context.translate(center_x, center_y); + context.rotate(tick as f64 * (PI / 12.)); + context.move_to(center_x, center_y); + context.line_to(center_x + 10., center_y); + let _ = context.stroke(); + context.identity_matrix(); + }); + } + } + }); + s } } diff --git a/dashboard/src/ui/pie_chart.rs b/dashboard/src/ui/pie_chart.rs deleted file mode 100644 index f51732d..0000000 --- a/dashboard/src/ui/pie_chart.rs +++ /dev/null @@ -1,141 +0,0 @@ -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>, - wedges: Rc>>, -} - -#[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) @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, -} - -impl PieChartBuilder { - pub fn rotation(mut self, rotation: f64) -> Self { - self.rotation = rotation; - self - } - - pub fn wedges(mut self, wedges: Vec) -> Self { - self.wedges = wedges; - self - } - - pub fn build(self) -> PieChart { - PieChart::new(self) - } -}