|
|
|
|
@ -27,11 +27,9 @@ fn font(height: u32) -> MonoFont<'static> {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub struct CalendarDay<C> { |
|
|
|
|
pub style: ComponentStyle<C>, |
|
|
|
|
pub top_left: Point, |
|
|
|
|
pub size: Size, |
|
|
|
|
pub fg_color: C, |
|
|
|
|
pub bg_color: C, |
|
|
|
|
pub border: u32, |
|
|
|
|
pub day_of_month: u32, |
|
|
|
|
pub has_event: bool, |
|
|
|
|
} |
|
|
|
|
@ -50,18 +48,21 @@ where
|
|
|
|
|
// Adding based on border so that the borders overlap
|
|
|
|
|
let date_rect = Rectangle::new( |
|
|
|
|
self.top_left, |
|
|
|
|
self.size + Size::new(self.border / 2 + 1, self.border / 2 + 1), |
|
|
|
|
self.size + Size::new(self.style.border / 2 + 1, self.style.border / 2 + 1), |
|
|
|
|
); |
|
|
|
|
date_rect |
|
|
|
|
.into_styled(PrimitiveStyle::with_fill(self.bg_color)) |
|
|
|
|
.into_styled(PrimitiveStyle::with_fill(self.style.bg_color)) |
|
|
|
|
.draw(target)?; |
|
|
|
|
date_rect |
|
|
|
|
.into_styled(PrimitiveStyle::with_stroke(self.fg_color, self.border)) |
|
|
|
|
.into_styled(PrimitiveStyle::with_stroke( |
|
|
|
|
self.style.border_color, |
|
|
|
|
self.style.border, |
|
|
|
|
)) |
|
|
|
|
.draw(target)?; |
|
|
|
|
|
|
|
|
|
let text = format!("{}", self.day_of_month); |
|
|
|
|
let date_font = font(self.size.height / 2); |
|
|
|
|
let text_style = MonoTextStyle::new(&date_font, self.fg_color); |
|
|
|
|
let text_style = MonoTextStyle::new(&date_font, self.style.fg_color); |
|
|
|
|
Text::new(&text, self.top_left, text_style) |
|
|
|
|
.align_to(&date_rect, horizontal::Center, vertical::Center) |
|
|
|
|
.draw(target)?; |
|
|
|
|
@ -76,7 +77,7 @@ where
|
|
|
|
|
self.size.height as i32 - event_padding, |
|
|
|
|
), |
|
|
|
|
) |
|
|
|
|
.into_styled(PrimitiveStyle::with_stroke(self.fg_color, 2)) |
|
|
|
|
.into_styled(PrimitiveStyle::with_stroke(self.style.fg_color, 2)) |
|
|
|
|
.draw(target)?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -203,12 +204,19 @@ where
|
|
|
|
|
(fg_color, bg_color, border) = (self.bg_color, self.hi_color.unwrap(), 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let calendar_day = CalendarDay { |
|
|
|
|
let style = ComponentStyle { |
|
|
|
|
fg_color, |
|
|
|
|
bg_color, |
|
|
|
|
hi_color: fg_color, |
|
|
|
|
border_color: fg_color, |
|
|
|
|
border, |
|
|
|
|
bezel: border, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let calendar_day = CalendarDay { |
|
|
|
|
style, |
|
|
|
|
top_left: self.top_left + Point::new((width * x) as i32, (height * y) as i32), |
|
|
|
|
size: Size::new(width, height), |
|
|
|
|
fg_color, |
|
|
|
|
bg_color, |
|
|
|
|
day_of_month: i - empty_squares + 1, |
|
|
|
|
has_event: i - empty_squares + 1 == date_now.day(), |
|
|
|
|
}; |
|
|
|
|
@ -219,47 +227,100 @@ where
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Clone)] |
|
|
|
|
pub struct ScrollingWeek { |
|
|
|
|
day: chrono::NaiveDate, |
|
|
|
|
year: i32, |
|
|
|
|
week: u32, |
|
|
|
|
start_of_month: bool, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl ScrollingWeek { |
|
|
|
|
pub fn succ(&self) -> ScrollingWeek { |
|
|
|
|
let start_of_next_month = self |
|
|
|
|
.day |
|
|
|
|
.with_month(self.day.month() % 11 + 1) |
|
|
|
|
.unwrap() |
|
|
|
|
.with_day(1) |
|
|
|
|
fn monday(&self) -> chrono::NaiveDate { |
|
|
|
|
chrono::NaiveDate::from_isoywd(self.year, self.week, chrono::Weekday::Mon) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn first_day_of_week(&self) -> Option<chrono::NaiveDate> { |
|
|
|
|
let monday = self.monday(); |
|
|
|
|
let next_monday = self |
|
|
|
|
.monday() |
|
|
|
|
.checked_add_signed(chrono::Duration::days(7)) |
|
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
let days_until_next_month = |
|
|
|
|
start_of_next_month.num_days_from_ce() - self.day.num_days_from_ce(); |
|
|
|
|
let day_of_week = self.day.weekday().number_from_monday() as i32; |
|
|
|
|
if !self.start_of_month || monday.month() == next_monday.month() { |
|
|
|
|
return Some(monday); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let days_to_skip = if days_until_next_month < 7 { |
|
|
|
|
days_until_next_month |
|
|
|
|
} else { |
|
|
|
|
8 - day_of_week |
|
|
|
|
}; |
|
|
|
|
if !self.start_of_month && next_monday.day() == 1 { |
|
|
|
|
return None; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return next_monday.with_day(1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn last_day_of_week(&self) -> Option<chrono::NaiveDate> { |
|
|
|
|
return self |
|
|
|
|
.succ() |
|
|
|
|
.first_day_of_week()? |
|
|
|
|
.checked_sub_signed(chrono::Duration::days(1)); |
|
|
|
|
|
|
|
|
|
match self.succ().first_day_of_week() { |
|
|
|
|
None => self |
|
|
|
|
.first_day_of_week()? |
|
|
|
|
.checked_add_signed(chrono::Duration::days(6)), |
|
|
|
|
Some(date) => date.checked_sub_signed(chrono::Duration::days(1)), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn from_date(date: chrono::NaiveDate) -> ScrollingWeek { |
|
|
|
|
let week = date.iso_week().week(); |
|
|
|
|
|
|
|
|
|
ScrollingWeek { |
|
|
|
|
day: self |
|
|
|
|
.day |
|
|
|
|
.checked_add_signed(chrono::Duration::days(days_to_skip as i64)) |
|
|
|
|
.unwrap(), |
|
|
|
|
year: date.year(), |
|
|
|
|
week, |
|
|
|
|
start_of_month: date.day() < 7, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn from_week(week: chrono::IsoWeek) -> ScrollingWeek { |
|
|
|
|
let now = chrono::Local::today().naive_local(); |
|
|
|
|
let monday = chrono::NaiveDate::from_isoywd(now.year(), week.week(), chrono::Weekday::Mon); |
|
|
|
|
|
|
|
|
|
ScrollingWeek { |
|
|
|
|
year: now.year(), |
|
|
|
|
week: week.week(), |
|
|
|
|
start_of_month: monday.day() < 7, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn succ(&self) -> ScrollingWeek { |
|
|
|
|
let monday = self.monday(); |
|
|
|
|
let next_monday = monday |
|
|
|
|
.checked_add_signed(chrono::Duration::days(7)) |
|
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
match self.start_of_month || monday.month() == next_monday.month() { |
|
|
|
|
false => ScrollingWeek { |
|
|
|
|
start_of_month: true, |
|
|
|
|
..*self |
|
|
|
|
}, |
|
|
|
|
true => ScrollingWeek { |
|
|
|
|
year: next_monday.year(), |
|
|
|
|
week: next_monday.iso_week().week(), |
|
|
|
|
start_of_month: false, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn month(&self) -> chrono::Month { |
|
|
|
|
chrono::Month::from_u32(self.day.month()).unwrap() |
|
|
|
|
chrono::Month::from_u32(self.monday().month()).unwrap() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn week(&self) -> u32 { |
|
|
|
|
self.day.iso_week().week() |
|
|
|
|
self.monday().iso_week().week() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn year(&self) -> i32 { |
|
|
|
|
self.day.year() |
|
|
|
|
self.monday().year() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -283,17 +344,14 @@ where
|
|
|
|
|
D: DrawTarget<Color = C>, |
|
|
|
|
{ |
|
|
|
|
let height = self.size.height / (1 + self.weeks * 2); |
|
|
|
|
let mut week = ScrollingWeek { |
|
|
|
|
day: chrono::NaiveDate::from_isoywd( |
|
|
|
|
self.day.year(), |
|
|
|
|
self.day.iso_week().week(), |
|
|
|
|
chrono::Weekday::Mon, |
|
|
|
|
) |
|
|
|
|
.checked_add_signed(chrono::Duration::days(-7 * self.weeks as i64)) |
|
|
|
|
.unwrap(), |
|
|
|
|
}; |
|
|
|
|
let mut week = ScrollingWeek::from_date( |
|
|
|
|
self |
|
|
|
|
.day |
|
|
|
|
.checked_sub_signed(chrono::Duration::days(self.weeks as i64 * 7)) |
|
|
|
|
.unwrap(), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
for i in 0..self.weeks * 2 { |
|
|
|
|
for i in 0..(1 + self.weeks * 2) { |
|
|
|
|
week = week.succ(); |
|
|
|
|
|
|
|
|
|
let calendar_week = CalendarWeek { |
|
|
|
|
@ -303,6 +361,7 @@ where
|
|
|
|
|
year: week.year(), |
|
|
|
|
month: week.month(), |
|
|
|
|
week: week.week(), |
|
|
|
|
scroll_week: week.clone(), |
|
|
|
|
}; |
|
|
|
|
calendar_week.draw(target)?; |
|
|
|
|
} |
|
|
|
|
@ -318,6 +377,7 @@ pub struct CalendarWeek<C> {
|
|
|
|
|
pub year: i32, |
|
|
|
|
pub month: chrono::Month, |
|
|
|
|
pub week: u32, |
|
|
|
|
pub scroll_week: ScrollingWeek, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<C> Drawable for CalendarWeek<C> |
|
|
|
|
@ -345,10 +405,55 @@ where
|
|
|
|
|
false => sunday, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let first_day = self.scroll_week.first_day_of_week(); |
|
|
|
|
let last_day = self.scroll_week.last_day_of_week(); |
|
|
|
|
|
|
|
|
|
if first_day.is_none() || last_day.is_none() { |
|
|
|
|
return Ok(()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let first_day = first_day.unwrap(); |
|
|
|
|
let last_day = last_day.unwrap(); |
|
|
|
|
|
|
|
|
|
let width = self.size.width / 7; |
|
|
|
|
|
|
|
|
|
if first_day.weekday().number_from_monday() > 4 { |
|
|
|
|
let month = CalendarMonth { |
|
|
|
|
top_left: self.top_left, |
|
|
|
|
size: Size::new( |
|
|
|
|
width * first_day.weekday().number_from_monday(), |
|
|
|
|
self.size.height, |
|
|
|
|
), |
|
|
|
|
border: self.style.border, |
|
|
|
|
fg_color: self.style.fg_color, |
|
|
|
|
bg_color: self.style.bg_color, |
|
|
|
|
month: chrono::Month::from_u32(first_day.month()).unwrap(), |
|
|
|
|
}; |
|
|
|
|
month.draw(target)?; |
|
|
|
|
} else if last_day.weekday().number_from_monday() < 4 { |
|
|
|
|
let month = CalendarMonth { |
|
|
|
|
top_left: self.top_left |
|
|
|
|
+ Point::new((width * last_day.weekday().number_from_monday()) as i32, 0), |
|
|
|
|
size: Size::new( |
|
|
|
|
width * (7 - last_day.weekday().number_from_monday()), |
|
|
|
|
self.size.height, |
|
|
|
|
), |
|
|
|
|
border: self.style.border, |
|
|
|
|
fg_color: self.style.fg_color, |
|
|
|
|
bg_color: self.style.bg_color, |
|
|
|
|
month: chrono::Month::from_u32( |
|
|
|
|
last_day |
|
|
|
|
.checked_add_signed(chrono::Duration::days(1)) |
|
|
|
|
.unwrap() |
|
|
|
|
.month(), |
|
|
|
|
) |
|
|
|
|
.unwrap(), |
|
|
|
|
}; |
|
|
|
|
month.draw(target)?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let mut weekday = first_day.weekday(); |
|
|
|
|
for i in first_day.weekday().number_from_monday()..(last_day.weekday().number_from_monday() + 1) |
|
|
|
|
for _ in first_day.weekday().number_from_monday()..(last_day.weekday().number_from_monday() + 1) |
|
|
|
|
{ |
|
|
|
|
let day = chrono::NaiveDate::from_isoywd(self.year, self.week, weekday); |
|
|
|
|
|
|
|
|
|
@ -368,11 +473,9 @@ where
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
let calendar_day = CalendarDay { |
|
|
|
|
style, |
|
|
|
|
top_left: self.top_left + Point::new((width * weekday.num_days_from_monday()) as i32, 0), |
|
|
|
|
size: Size::new(width, self.size.height), |
|
|
|
|
border: self.style.border, |
|
|
|
|
fg_color, |
|
|
|
|
bg_color, |
|
|
|
|
day_of_month: day.day(), |
|
|
|
|
has_event: day.num_days_from_ce() == today.num_days_from_ce(), |
|
|
|
|
}; |
|
|
|
|
|