rat_widget/calendar/
calendar3.rs

1use crate::calendar::{CalendarSelection, CalendarState, CalendarStyle, Month};
2use chrono::NaiveDate;
3use ratatui::buffer::Buffer;
4use ratatui::layout::{Alignment, Direction, Rect};
5use ratatui::style::Style;
6use ratatui::widgets::{Block, StatefulWidget};
7use std::collections::HashMap;
8use std::marker::PhantomData;
9use std::mem;
10
11///
12/// Calendar with 3 months on display.
13///
14/// Take this as sample for your own fancy calendar.
15///
16/// ```rust
17/// # use std::collections::HashMap;
18/// # use chrono::Local;
19/// # use pure_rust_locales::Locale;
20/// # use ratatui::buffer::Buffer;
21/// # use ratatui::layout::{Alignment, Direction};
22/// # use ratatui::prelude::Rect;
23/// # use ratatui::widgets::{Block, StatefulWidget};
24/// # use rat_widget::calendar::{Calendar3, CalendarState, CalendarStyle, TodayPolicy};
25/// # use rat_widget::calendar::selection::SingleSelection;
26///
27/// # let mut buf = Buffer::empty(Rect::new(0, 0, 24, 24));
28///
29/// let mut style = CalendarStyle::default();
30///
31/// let mut day_styles = HashMap::default();
32///
33/// let mut state = CalendarState::<3, SingleSelection>::new();
34/// state.set_step(1);
35/// state.set_primary_idx(1);
36/// state.set_today_policy(TodayPolicy::Index(1));
37/// state.set_start_date(Local::now().date_naive());
38///
39/// Calendar3::new()
40///         .direction(Direction::Vertical)
41///         .locale(Locale::default())
42///         .styles(style)
43///         .title_align(Alignment::Left)
44///         .day_styles(&day_styles)
45///         .show_weekdays()
46///         .block(Block::bordered())
47///         .render(Rect::new(0,0,24,24), &mut buf, &mut state);
48///
49/// ```
50///
51#[derive(Debug, Default)]
52pub struct Calendar3<'a, Selection> {
53    direction: Direction,
54    months: [Month<'a, Selection>; 3],
55    phantom: PhantomData<Selection>,
56}
57
58impl<'a, Selection> Calendar3<'a, Selection> {
59    pub fn new() -> Self
60    where
61        Selection: Default,
62    {
63        Self::default()
64    }
65
66    /// Locale for month-names, day-names.
67    #[inline]
68    pub fn locale(mut self, loc: chrono::Locale) -> Self {
69        for i in 0..3 {
70            self.months[i] = mem::take(&mut self.months[i]).locale(loc);
71        }
72        self
73    }
74
75    #[inline]
76    pub fn direction(mut self, direction: Direction) -> Self {
77        self.direction = direction;
78        self
79    }
80
81    /// Show weekday titles
82    #[inline]
83    pub fn show_weekdays(mut self) -> Self {
84        for i in 0..3 {
85            self.months[i] = mem::take(&mut self.months[i]).show_weekdays();
86        }
87        self
88    }
89
90    /// Set the composite style.
91    #[inline]
92    pub fn styles(mut self, s: CalendarStyle) -> Self {
93        for i in 0..3 {
94            self.months[i] = mem::take(&mut self.months[i]).styles(s.clone());
95        }
96        self
97    }
98
99    /// Style for the selected tab.
100    pub fn select_style(mut self, style: Style) -> Self {
101        for i in 0..3 {
102            self.months[i] = mem::take(&mut self.months[i]).select_style(style);
103        }
104        self
105    }
106
107    /// Style for a focused tab.
108    pub fn focus_style(mut self, style: Style) -> Self {
109        for i in 0..3 {
110            self.months[i] = mem::take(&mut self.months[i]).focus_style(style);
111        }
112        self
113    }
114
115    /// Sets the default day-style.
116    #[inline]
117    pub fn day_style(mut self, s: impl Into<Style>) -> Self {
118        let s = s.into();
119        for i in 0..3 {
120            self.months[i] = mem::take(&mut self.months[i]).day_style(s);
121        }
122        self
123    }
124
125    /// Sets all the day-styles.
126    #[inline]
127    pub fn day_styles(mut self, styles: &'a HashMap<NaiveDate, Style>) -> Self {
128        for i in 0..3 {
129            self.months[i] = mem::take(&mut self.months[i]).day_styles(styles);
130        }
131        self
132    }
133
134    /// Set the week number style
135    #[inline]
136    pub fn week_style(mut self, s: impl Into<Style>) -> Self {
137        let s = s.into();
138        for i in 0..3 {
139            self.months[i] = mem::take(&mut self.months[i]).week_style(s);
140        }
141        self
142    }
143
144    /// Set the week day style
145    #[inline]
146    pub fn weekday_style(mut self, s: impl Into<Style>) -> Self {
147        let s = s.into();
148        for i in 0..3 {
149            self.months[i] = mem::take(&mut self.months[i]).weekday_style(s);
150        }
151        self
152    }
153
154    /// Set the month-name style.
155    #[inline]
156    pub fn title_style(mut self, s: impl Into<Style>) -> Self {
157        let s = s.into();
158        for i in 0..3 {
159            self.months[i] = mem::take(&mut self.months[i]).title_style(s);
160        }
161        self
162    }
163
164    /// Set the mont-name align.
165    #[inline]
166    pub fn title_align(mut self, a: Alignment) -> Self {
167        for i in 0..3 {
168            self.months[i] = mem::take(&mut self.months[i]).title_align(a);
169        }
170        self
171    }
172
173    /// Block
174    #[inline]
175    pub fn block(mut self, b: Block<'a>) -> Self {
176        for i in 0..3 {
177            self.months[i] = mem::take(&mut self.months[i]).block(b.clone());
178        }
179        self
180    }
181}
182
183impl<Selection> StatefulWidget for Calendar3<'_, Selection>
184where
185    Selection: CalendarSelection,
186{
187    type State = CalendarState<3, Selection>;
188
189    #[allow(deprecated)]
190    fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
191        state.area = area;
192        state.inner = area;
193        state.widget_area = area;
194
195        match self.direction {
196            Direction::Horizontal => {
197                let width = self.months[0].width();
198                let height = self
199                    .months
200                    .iter()
201                    .enumerate()
202                    .map(|(i, v)| v.height(&state.months[i]))
203                    .max()
204                    .expect("height");
205
206                let mut area = Rect::new(area.x, area.y, width, height);
207                for i in 0..3 {
208                    mem::take(&mut self.months[i]).render(area, buf, &mut state.months[i]);
209                    area.x += area.width + 2;
210                }
211            }
212            Direction::Vertical => {
213                let width = self.months[0].width();
214
215                let mut area = Rect::new(area.x, area.y, width, 0);
216                for i in 0..3 {
217                    area.height = self.months[i].height(&state.months[0]);
218                    mem::take(&mut self.months[i]).render(area, buf, &mut state.months[i]);
219                    area.y += area.height + 1;
220                }
221            }
222        }
223    }
224}