mod model; use gtk4 as gtk; use chrono::{Datelike, NaiveDate, NaiveTime, Weekday}; use gtk::gdk::Display; use gtk::prelude::*; use crate::model::event::{Event, Time}; static DAYS: [&str; 7] = ["LUN", "MAR", "MER", "JEU", "VEN", "SAM", "DIM"]; static MONTHES: [&str; 12] = [ "Jan", "Fév", "Mar", "Avr", "Mai", "Juin", "Juil", "Aoû", "Sep", "Oct", "Nov", "Déc", ]; fn main() { let mut events = [ Event { date: NaiveDate::from_ymd(2021, 11, 22), time: Time::AllDay, name: "Début de la semaine".to_string(), }, Event { date: NaiveDate::from_ymd(2021, 11, 26), time: Time::AllDay, name: "Fin de la semaine".to_string(), }, Event { date: NaiveDate::from_ymd(2021, 11, 26), time: Time::Time { start: NaiveTime::from_hms(15, 0, 0), end: Some(NaiveTime::from_hms(15, 30, 0)), }, name: "Appel".to_string(), }, Event { date: NaiveDate::from_ymd(2021, 11, 26), time: Time::Time { start: NaiveTime::from_hms(12, 0, 0), end: Some(NaiveTime::from_hms(14, 0, 0)), }, name: "Repas".to_string(), }, Event { date: NaiveDate::from_ymd(2021, 11, 26), time: Time::Time { start: NaiveTime::from_hms(8, 0, 0), end: None, }, name: "Promener le chien".to_string(), }, Event { date: NaiveDate::from_ymd(2021, 11, 26), time: Time::Time { start: NaiveTime::from_hms(9, 0, 0), end: None, }, name: "Thé".to_string(), }, ] .to_vec(); events.sort_by_key(|e| e.time); let application = gtk::Application::new(Some("me.guyonvarch.calendar"), Default::default()); application.connect_startup(move |app| build_ui(app, &events)); application.run(); } fn build_ui(app: >k::Application, events: &Vec) { let window = gtk::ApplicationWindow::new(app); window.set_title(Some("Calendar")); window.set_default_size(800, 600); load_style(); let grid = gtk::Grid::builder().build(); window.set_child(Some(&grid)); for col in 0..7 { grid.attach(&day_title(col), col, 0, 1, 1); } let today = chrono::offset::Local::today().naive_utc(); let last_monday = NaiveDate::from_isoywd(today.year(), today.iso_week().week(), Weekday::Mon); let mut d = last_monday; for row in 1..5 { for col in 0..7 { grid.attach(&day_entry(&d, &today, &events), col, row, 1, 1); d = d.succ(); } } window.show(); } fn load_style() { let provider = gtk::CssProvider::new(); provider.load_from_data(include_bytes!("style.css")); gtk::StyleContext::add_provider_for_display( &Display::default().expect("Error initializing gtk css provider."), &provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, ); } fn day_title(col: i32) -> gtk::Box { let vbox = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .build(); vbox.add_css_class("g-Calendar__DayTitle"); let label = gtk::Label::builder().label(DAYS[col as usize]).build(); vbox.append(&label); vbox } fn day_entry(date: &NaiveDate, today: &NaiveDate, events: &Vec) -> gtk::ScrolledWindow { let vbox = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .build(); vbox.add_css_class("g-Calendar__Day"); if date == today { vbox.add_css_class("g-Calendar__Day--Today"); } vbox.append(&day_label(date)); let events = events .iter() .filter(|e| e.date == *date) .collect::>(); if !events.is_empty() { vbox.append(&day_events(events)); } let scrolled_window = gtk::ScrolledWindow::builder() .hscrollbar_policy(gtk::PolicyType::Never) .hexpand(true) .vexpand(true) .child(&vbox) .build(); scrolled_window } fn day_label(date: &NaiveDate) -> gtk::Label { let label = gtk::Label::builder() .label(&format!( "{} {}", date.day(), MONTHES[date.month0() as usize] )) .halign(gtk::Align::Start) .build(); label.add_css_class("g-Calendar__DayNumber"); label } fn day_events(events: Vec<&Event>) -> gtk::Box { let vbox = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .build(); for event in events { let hbox = gtk::Box::builder() .orientation(gtk::Orientation::Horizontal) .hexpand(true) .build(); hbox.add_css_class("g-Calendar__DayEvent"); let event_txt = &event.pprint(); let label = gtk::Label::builder() .label(&event_txt) .ellipsize(pango::EllipsizeMode::End) .tooltip_text(&event_txt) .halign(gtk::Align::Start) .build(); hbox.append(&label); vbox.append(&hbox); } vbox }