diff options
-rw-r--r-- | karlgui/src/globals.rs | 18 | ||||
-rw-r--r-- | karlgui/src/views/calendar.rs | 195 |
2 files changed, 136 insertions, 77 deletions
diff --git a/karlgui/src/globals.rs b/karlgui/src/globals.rs index 202cce6..48af280 100644 --- a/karlgui/src/globals.rs +++ b/karlgui/src/globals.rs @@ -52,23 +52,7 @@ impl Globals { } } } - pub fn get_all_instances_range( - &mut self, - start: NaiveDateTime, - end: NaiveDateTime, - ) -> Option<Vec<(u64, Range<Option<NaiveDateTime>>)>> { - let mut l = vec![]; - for t in &self.tasks.values().map(|e| e.id).collect::<Vec<_>>() { - if let Some(r) = self.get_instances_range(*t, start, end) { - l.extend(r.into_iter().map(|e| (*t, e.clone()))); - } - } - if l.len() > 0 { - Some(l) - } else { - None - } - } + pub fn get_instances_range( &mut self, task: u64, diff --git a/karlgui/src/views/calendar.rs b/karlgui/src/views/calendar.rs index a861c73..ecb70dd 100644 --- a/karlgui/src/views/calendar.rs +++ b/karlgui/src/views/calendar.rs @@ -1,9 +1,8 @@ -use std::ops::Range; - use crate::{helper::weekday_to_str, Globals}; -use chrono::{Duration, NaiveDateTime}; -use egui::{Color32, Sense, Stroke, Ui, Vec2}; -use egui_extras::TableBuilder; +use chrono::{Datelike, Duration, NaiveDateTime, Timelike}; +use egui::{Color32, Label, Rect, ScrollArea, Sense, Stroke, Ui, Vec2}; +use egui_extras::{Size, StripBuilder}; +use std::{collections::BTreeMap, ops::Range}; #[derive(Default)] pub struct Calendar { @@ -17,67 +16,143 @@ impl Calendar { let start_dt = start_date.and_hms(0, 0, 0); let end_dt = end_date.and_hms(0, 0, 0); - let instances = if let Some(instances) = g.get_all_instances_range(start_dt, end_dt) { - instances - } else { - ui.horizontal(|ui| { - ui.spinner(); - ui.label("Loading…"); - }); - return; - }; + let task_ids = g.tasks.keys().map(|e| e.to_owned()).collect::<Vec<_>>(); + let instances = + BTreeMap::from_iter(task_ids.iter().filter_map(|id| { + Some((id, g.get_instances_range(*id, start_dt, end_dt).to_owned()?)) + })); - let height = 50.0; + let height = 2000.0; - TableBuilder::new(ui) - .column(egui_extras::Size::exact(50.0)) - .columns(egui_extras::Size::remainder(), 7) - .header(25.0, |mut ui| { - ui.col(|_| {}); - for d in 0..7 { - ui.col(|ui| { - ui.heading(weekday_to_str(d)); + ScrollArea::vertical().show(ui, |ui| { + StripBuilder::new(ui) + .size(Size::exact(50.0)) + .sizes(Size::remainder(), 7) + .horizontal(|mut ui| { + ui.cell(|ui| { + for h in 0..24 { + ui.add_sized( + Vec2::new(50.0, height / 24.0), + Label::new(&format!("{h:02}:00")), + ); + } }); - } - }) - .body(|mut ui| { - let mut cols: [Vec<u64>; 7] = - [vec![], vec![], vec![], vec![], vec![], vec![], vec![]]; - for h in 0..24 { - ui.row(height, |mut ui| { - ui.col(|ui| { - ui.heading(&format!("{h:02}:00")); - }); - for d in 0..7 { - let _col = &mut cols[d]; - let time = start_dt + Duration::days(d as i64) + Duration::hours(h); - let time_end = time + Duration::hours(1) - Duration::seconds(1); - let instances_here = - instances.iter().filter(|(_, r)| r.overlaps(time..time_end)); + for d in 0..7 { + ui.cell(|ui| { + let time = start_dt + Duration::days(d as i64); + let time_end = time + Duration::days(1) - Duration::seconds(1); + let instances_here = instances + .iter() + .map(|(id, rs)| { + ( + id, + rs.iter() + .filter(|r| r.overlaps(time..time_end)) + .collect::<Vec<_>>(), + ) + }) + .filter(|(_, l)| l.len() != 0); + + ui.vertical(|ui| { + ui.heading(weekday_to_str( + time.date().weekday().num_days_from_monday().into(), + )); + ui.horizontal(|ui| { + for (id, rs) in instances_here { + let task = g.tasks.get(id).unwrap(); + + let (rect, response) = ui.allocate_exact_size( + Vec2::new(10.0, height), + Sense::hover(), + ); - ui.col(|ui| { - for (id, _) in instances_here { - let task = g.tasks.get(id).unwrap(); - let (rect, response) = - ui.allocate_at_least(Vec2::new(10.0, 50.0), Sense::hover()); - ui.painter().rect( - rect, - 0.0, - Color32::KHAKI, - Stroke::new(0.0, Color32::WHITE), - ); - response.on_hover_ui_at_pointer(|ui| { - ui.heading(&task.name); - if let Some(d) = &task.description { - ui.label(d); + for r in &rs { + let r = + r.start.unwrap_or(time)..r.end.unwrap_or(time_end); + let rect_start = (r.start.hour() as f32 + + (r.start.minute() as f32 / 60.0)) + / 24.0 + * height; + let rect_end = (r.end.hour() as f32 + + (r.end.minute() as f32 / 60.0)) + / 24.0 + * height; + ui.painter().rect( + Rect::from_two_pos( + rect.min + Vec2::new(0.0, rect_start), + rect.min + Vec2::new(10.0, rect_end), + ), + 0.0, + Color32::KHAKI, + Stroke::new(0.0, Color32::WHITE), + ); } - }); - } + + response.on_hover_ui_at_pointer(|ui| { + ui.heading(&task.name); + if let Some(d) = &task.description { + ui.label(d); + } + }); + } + }) }); - } - }) - } - }) + // }); + // }); + }); + } + }); + }); + + // TableBuilder::new(ui) + // .column(egui_extras::Size::exact(50.0)) + // .columns(egui_extras::Size::remainder(), 7) + // .header(25.0, |mut ui| { + // ui.col(|_| {}); + // for d in 0..7 { + // ui.col(|ui| { + // ui.heading(weekday_to_str(d)); + // }); + // } + // }) + // .body(|mut ui| { + // let mut cols: [Vec<u64>; 7] = + // [vec![], vec![], vec![], vec![], vec![], vec![], vec![]]; + // for h in 0..24 { + // ui.row(height, |mut ui| { + // ui.col(|ui| { + // ui.heading(&format!("{h:02}:00")); + // }); + // for d in 0..7 { + // let _col = &mut cols[d]; + // let time = start_dt + Duration::days(d as i64) + Duration::hours(h); + // let time_end = time + Duration::hours(1) - Duration::seconds(1); + // let instances_here = + // instances.iter().filter(|(_, r)| r.overlaps(time..time_end)); + + // ui.col(|ui| { + // for (id, _) in instances_here { + // let task = g.tasks.get(id).unwrap(); + // let (rect, response) = + // ui.allocate_at_least(Vec2::new(10.0, 50.0), Sense::hover()); + // ui.painter().rect( + // rect, + // 0.0, + // Color32::KHAKI, + // Stroke::new(0.0, Color32::WHITE), + // ); + // response.on_hover_ui_at_pointer(|ui| { + // ui.heading(&task.name); + // if let Some(d) = &task.description { + // ui.label(d); + // } + // }); + // } + // }); + // } + // }) + // } + // }) } } |