rat_widget/calendar/
calendar3.rs

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