Totally rewrite dashboard as a GTK application #54
|
@ -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<Wedge>,
|
||||
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<Item = Wedge>) -> Self {
|
||||
let mut wedges: Vec<Wedge> = 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();
|
||||
}
|
||||
}
|
|
@ -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<RefCell<Option<SunMoon>>>,
|
||||
chart: Rc<RefCell<PieChart>>,
|
||||
}
|
||||
|
||||
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<TransitClockPrivate>) @extends gtk::Box, gtk::Widget;
|
||||
pub struct TransitClock(ObjectSubclass<TransitClockPrivate>) @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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue