rat_widget/
calendar.rs

1//!
2//! Calendar widgets.
3//!
4//! There's a Month widget to render one month of a calendar.
5//! This has limited behaviour and no built-in scrolling.
6//! Use a CalendarState<1> if you need that.
7//!
8//! There is no Calendar widget as such, but there is a CalendarState
9//! that can manage N months as a full calendar. With movement/scrolling/selection
10//! over all months.
11//!
12//! There is a Calendar3 widget that can display 3 months in a line/column.
13//! Use this as a baseline for other layouts.
14//!
15//! There are 3 selection-models that can be used:
16//! - [NoSelection](selection::NoSelection)  Scrolling is still possible.
17//! - [SingleSelection](selection::SingleSelection) Selection of a single day.
18//! - [RangeSelection](selection::RangeSelection) Selection of any date range.
19//!
20
21use chrono::{Datelike, Days, Months, NaiveDate};
22
23#[allow(clippy::module_inception)]
24mod calendar;
25mod calendar3;
26pub(crate) mod event;
27mod month;
28mod no_selection;
29mod range_selection;
30mod single_selection;
31mod style;
32
33pub use calendar::*;
34pub use calendar3::*;
35pub use month::*;
36pub use style::*;
37
38/// Selection model for a calendar.
39#[allow(clippy::len_without_is_empty)]
40pub trait CalendarSelection {
41    /// Select day count.
42    fn count(&self) -> usize;
43
44    /// Is the given day selected.
45    fn is_selected(&self, date: NaiveDate) -> bool;
46
47    /// Selection lead, or the sole selected day.
48    fn lead_selection(&self) -> Option<NaiveDate>;
49}
50
51pub mod selection {
52    use crate::calendar::CalendarSelection;
53    use chrono::NaiveDate;
54    use std::cell::RefCell;
55    use std::rc::Rc;
56
57    pub use super::no_selection::*;
58    pub use super::range_selection::*;
59    pub use super::single_selection::*;
60
61    impl<T: CalendarSelection> CalendarSelection for Rc<RefCell<T>> {
62        fn count(&self) -> usize {
63            self.borrow().count()
64        }
65
66        fn is_selected(&self, date: NaiveDate) -> bool {
67            self.borrow().is_selected(date)
68        }
69
70        fn lead_selection(&self) -> Option<NaiveDate> {
71            self.borrow().lead_selection()
72        }
73    }
74}
75
76fn is_first_day_of_month(date: NaiveDate) -> bool {
77    date.day() == 1
78}
79
80fn is_last_day_of_month(date: NaiveDate) -> bool {
81    date.month() != (date + Days::new(1)).month()
82}
83
84fn first_day_of_month(date: NaiveDate) -> NaiveDate {
85    date.with_day(1).expect("date")
86}
87
88fn last_day_of_month(date: NaiveDate) -> NaiveDate {
89    date.with_day(1).expect("date") + Months::new(1) - Days::new(1)
90}
91
92fn is_same_month(start: NaiveDate, end: NaiveDate) -> bool {
93    start.year() == end.year() && start.month() == end.month()
94}
95
96fn is_same_week(start: NaiveDate, end: NaiveDate) -> bool {
97    start.iso_week() == end.iso_week()
98}