1use crate::_private::NonExhaustive;
2use crate::calendar::event::CalOutcome;
3use crate::calendar::selection::{NoSelection, RangeSelection, SingleSelection};
4use crate::calendar::style::CalendarStyle;
5use crate::calendar::{CalendarSelection, first_day_of_month, last_day_of_month};
6use crate::text::HasScreenCursor;
7use crate::util::{block_size, revert_style};
8use chrono::{Datelike, Days, NaiveDate, Weekday};
9use rat_event::util::MouseFlagsN;
10use rat_focus::{FocusBuilder, FocusFlag, HasFocus};
11use rat_reloc::RelocatableState;
12use ratatui::buffer::Buffer;
13use ratatui::layout::{Alignment, Rect};
14use ratatui::style::Stylize;
15use ratatui::style::{Style, Styled};
16use ratatui::text::Span;
17use ratatui::widgets::block::Title;
18use ratatui::widgets::{Block, StatefulWidget, Widget};
19use std::cell::RefCell;
20use std::cmp::max;
21use std::collections::HashMap;
22use std::marker::PhantomData;
23use std::rc::Rc;
24
25#[derive(Debug, Clone)]
54pub struct Month<'a, Selection> {
55 start_date: Option<NaiveDate>,
57
58 style: Style,
60 block: Option<Block<'a>>,
62 title_style: Option<Style>,
64 title_align: Alignment,
66 weeknum_style: Option<Style>,
68 weekday_style: Option<Style>,
70 day_style: Option<Style>,
72 day_styles: Option<&'a HashMap<NaiveDate, Style>>,
74 select_style: Option<Style>,
76 focus_style: Option<Style>,
78
79 hide_year: bool,
81 hide_month: bool,
83 hide_weekdays: bool,
85
86 loc: chrono::Locale,
88
89 phantom: PhantomData<Selection>,
90}
91
92#[derive(Debug)]
94pub struct MonthState<Selection = SingleSelection> {
95 pub area: Rect,
98 pub inner: Rect,
101 pub area_cal: Rect,
104 pub area_days: [Rect; 31],
107 pub area_weeknum: Rect,
110 pub area_weeks: [Rect; 6],
113
114 start_date: NaiveDate,
116
117 pub selection: Rc<RefCell<Selection>>,
120
121 pub container: Option<FocusFlag>,
124
125 pub focus: FocusFlag,
128 pub mouse: MouseFlagsN,
131
132 pub non_exhaustive: NonExhaustive,
133}
134
135impl<Selection> Default for Month<'_, Selection> {
136 fn default() -> Self {
137 Self {
138 start_date: None,
139 style: Default::default(),
140 title_style: Default::default(),
141 title_align: Default::default(),
142 weeknum_style: Default::default(),
143 weekday_style: Default::default(),
144 day_style: Default::default(),
145 day_styles: Default::default(),
146 select_style: Default::default(),
147 focus_style: Default::default(),
148 hide_year: Default::default(),
149 hide_month: Default::default(),
150 hide_weekdays: Default::default(),
151 block: Default::default(),
152 loc: Default::default(),
153 phantom: PhantomData,
154 }
155 }
156}
157
158impl<'a, Selection> Month<'a, Selection> {
159 pub fn new() -> Self {
161 Self::default()
162 }
163
164 #[inline]
167 pub fn date(mut self, s: NaiveDate) -> Self {
168 self.start_date = Some(first_day_of_month(s));
169 self
170 }
171
172 #[inline]
174 pub fn locale(mut self, loc: chrono::Locale) -> Self {
175 self.loc = loc;
176 self
177 }
178
179 #[inline]
181 pub fn hide_year(mut self) -> Self {
182 self.hide_year = true;
183 self
184 }
185
186 #[inline]
188 pub fn hide_month(mut self) -> Self {
189 self.hide_month = true;
190 self
191 }
192
193 #[inline]
195 pub fn show_year(mut self) -> Self {
196 self.hide_year = false;
197 self
198 }
199
200 #[inline]
202 #[deprecated(since = "2.3.0", note = "typo, use show_month()")]
203 pub fn show_show_month(mut self) -> Self {
204 self.hide_month = false;
205 self
206 }
207
208 #[inline]
210 pub fn show_month(mut self) -> Self {
211 self.hide_month = false;
212 self
213 }
214
215 #[inline]
217 pub fn hide_weekdays(mut self) -> Self {
218 self.hide_weekdays = true;
219 self
220 }
221
222 #[inline]
224 pub fn show_weekdays(mut self) -> Self {
225 self.hide_weekdays = false;
226 self
227 }
228
229 #[inline]
231 pub fn styles(mut self, styles: CalendarStyle) -> Self {
232 self.style = styles.style;
233 if let Some(border_style) = styles.border_style {
234 self.block = self.block.map(|v| v.border_style(border_style));
235 }
236 if let Some(title_style) = styles.title_style {
237 self.block = self.block.map(|v| v.title_style(title_style));
238 }
239 self.block = self.block.map(|v| v.style(self.style));
240 if styles.block.is_some() {
241 self.block = styles.block;
242 }
243 if styles.title.is_some() {
244 self.title_style = styles.title;
245 }
246 if styles.weeknum.is_some() {
247 self.weeknum_style = styles.weeknum;
248 }
249 if styles.weekday.is_some() {
250 self.weekday_style = styles.weekday;
251 }
252 if styles.day.is_some() {
253 self.day_style = styles.day;
254 }
255 if styles.select.is_some() {
256 self.select_style = styles.select;
257 }
258 if styles.focus.is_some() {
259 self.focus_style = styles.focus;
260 }
261
262 self
263 }
264
265 pub fn style(mut self, style: Style) -> Self {
267 self.style = style;
268 self.block = self.block.map(|v| v.set_style(style));
269 self
270 }
271
272 pub fn select_style(mut self, style: Style) -> Self {
274 self.select_style = Some(style);
275 self
276 }
277
278 pub fn focus_style(mut self, style: Style) -> Self {
280 self.focus_style = Some(style);
281 self
282 }
283
284 #[inline]
286 pub fn day_style(mut self, s: impl Into<Style>) -> Self {
287 self.day_style = Some(s.into());
288 self
289 }
290
291 #[inline]
293 pub fn day_styles(mut self, styles: &'a HashMap<NaiveDate, Style>) -> Self {
294 self.day_styles = Some(styles);
295 self
296 }
297
298 #[inline]
300 pub fn week_style(mut self, s: impl Into<Style>) -> Self {
301 self.weeknum_style = Some(s.into());
302 self
303 }
304
305 #[inline]
307 pub fn weekday_style(mut self, s: impl Into<Style>) -> Self {
308 self.weekday_style = Some(s.into());
309 self
310 }
311
312 #[inline]
314 pub fn title_style(mut self, s: impl Into<Style>) -> Self {
315 self.title_style = Some(s.into());
316 self
317 }
318
319 #[inline]
321 pub fn title_align(mut self, a: Alignment) -> Self {
322 self.title_align = a;
323 self
324 }
325
326 #[inline]
328 pub fn block(mut self, b: Block<'a>) -> Self {
329 self.block = Some(b);
330 self.block = self.block.map(|v| v.style(self.style));
331 self
332 }
333
334 #[inline]
336 pub fn width(&self) -> u16 {
337 8 * 3 + block_size(&self.block).width
338 }
339
340 #[inline]
343 pub fn height(&self, state: &MonthState<Selection>) -> u16 {
344 let start_date = if let Some(start_date) = self.start_date {
345 start_date
346 } else {
347 state.start_date
348 };
349
350 let r = MonthState::<Selection>::count_weeks(start_date) as u16;
351 let w = if !self.hide_weekdays { 1 } else { 0 };
352 let b = max(1, block_size(&self.block).height);
353 r + w + b
354 }
355}
356
357impl<'a, Selection> StatefulWidget for &Month<'a, Selection>
358where
359 Selection: CalendarSelection,
360{
361 type State = MonthState<Selection>;
362
363 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
364 render_ref(self, area, buf, state);
365 }
366}
367
368impl<Selection> StatefulWidget for Month<'_, Selection>
369where
370 Selection: CalendarSelection,
371{
372 type State = MonthState<Selection>;
373
374 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
375 render_ref(&self, area, buf, state);
376 }
377}
378
379fn render_ref<Selection: CalendarSelection>(
380 widget: &Month<'_, Selection>,
381 area: Rect,
382 buf: &mut Buffer,
383 state: &mut MonthState<Selection>,
384) {
385 state.area = area;
386 if let Some(start_date) = widget.start_date {
387 state.start_date = start_date;
388 }
389
390 let mut day = state.start_date;
391
392 let focus_style = widget.focus_style.unwrap_or(revert_style(widget.style));
393 let select_style = if let Some(select_style) = widget.select_style {
394 if state.is_container_focused() || state.is_focused() {
395 focus_style
396 } else {
397 select_style
398 }
399 } else {
400 if state.is_container_focused() || state.is_focused() {
401 focus_style
402 } else {
403 revert_style(widget.style)
404 }
405 };
406 let day_style = widget.day_style.unwrap_or(widget.style);
407 let week_style = widget.weeknum_style.unwrap_or(widget.style);
408 let weekday_style = widget.weekday_style.unwrap_or(widget.style);
409
410 let title_style = if let Some(title_style) = widget.title_style {
411 title_style
412 } else {
413 widget.style
414 };
415 let title_style = if state.is_focused() {
416 title_style.patch(focus_style)
417 } else {
418 title_style
419 };
420
421 let mut block = if let Some(block) = widget.block.clone() {
422 block
423 } else {
424 Block::new().style(widget.style)
425 };
426 let title_format = if !widget.hide_month {
427 if !widget.hide_year { "%B %Y" } else { "%B" }
428 } else {
429 ""
430 };
431 if !title_format.is_empty() {
432 block = block
433 .title(Title::from(
434 day.format_localized(title_format, widget.loc).to_string(),
435 ))
436 .title_style(title_style)
437 .title_alignment(widget.title_align)
438 }
439 state.inner = block.inner(area);
440 block.render(area, buf);
441
442 let month = day.month();
443 let mut w = 0;
444 let mut x = state.inner.x;
445 let mut y = state.inner.y;
446
447 if !widget.hide_weekdays {
449 let mut week_0 = day.week(Weekday::Mon).first_day();
450
451 x += 3;
452 buf.set_style(Rect::new(x, y, 3 * 7, 1), weekday_style);
453 for _ in 0..7 {
454 let area = Rect::new(x, y, 2, 1).intersection(state.inner);
455
456 let day_name = week_0.format_localized("%a", widget.loc).to_string();
457 Span::from(format!("{:2} ", day_name)).render(area, buf);
458
459 x += 3;
460 week_0 = week_0 + Days::new(1);
461 }
462 x = state.inner.x;
463 y += 1;
464 }
465
466 for i in 0..31 {
468 state.area_days[i] = Rect::default();
469 }
470 for i in 0..6 {
471 state.area_weeks[i] = Rect::default();
472 }
473 state.area_cal = Rect::new(x + 3, y, 7 * 3, state.week_len() as u16);
474 state.area_weeknum = Rect::new(x, y, 3, state.week_len() as u16);
475
476 state.area_weeks[w] = Rect::new(x, y, 2, 1).intersection(state.inner);
478 Span::from(day.format_localized("%V", widget.loc).to_string())
479 .style(week_style)
480 .render(state.area_weeks[w], buf);
481
482 x += 3;
483
484 for wd in [
485 Weekday::Mon,
486 Weekday::Tue,
487 Weekday::Wed,
488 Weekday::Thu,
489 Weekday::Fri,
490 Weekday::Sat,
491 Weekday::Sun,
492 ] {
493 if day.weekday() != wd {
494 x += 3;
495 } else {
496 let day_style = calc_day_style(widget, state, day, day_style, select_style);
497 state.area_days[day.day0() as usize] = Rect::new(x, y, 2, 1).intersection(state.inner);
498
499 Span::from(day.format_localized("%e", widget.loc).to_string())
500 .style(day_style)
501 .render(state.area_days[day.day0() as usize], buf);
502
503 if wd != Weekday::Sun && state.selection.is_selected(day + Days::new(1)) {
504 let mut gap_area = state.area_days[day.day0() as usize];
505 gap_area.x += 2;
506 gap_area.width = 1;
507 Span::from(" ").style(day_style).render(gap_area, buf);
508 }
509
510 x += 3;
511 day = day + Days::new(1);
512 }
513 }
514
515 w += 1;
516 x = state.inner.x;
517 y += 1;
518
519 while month == day.month() {
520 state.area_weeks[w] = Rect::new(x, y, 2, 1).intersection(state.inner);
521 Span::from(day.format_localized("%V", widget.loc).to_string())
522 .style(week_style)
523 .render(state.area_weeks[w], buf);
524
525 x += 3;
526
527 for wd in [
528 Weekday::Mon,
529 Weekday::Tue,
530 Weekday::Wed,
531 Weekday::Thu,
532 Weekday::Fri,
533 Weekday::Sat,
534 Weekday::Sun,
535 ] {
536 if day.month() == month {
537 let day_style = calc_day_style(widget, state, day, day_style, select_style);
538
539 state.area_days[day.day0() as usize] =
540 Rect::new(x, y, 2, 1).intersection(state.inner);
541
542 Span::from(day.format_localized("%e", widget.loc).to_string())
543 .style(day_style)
544 .render(state.area_days[day.day0() as usize], buf);
545
546 if wd != Weekday::Sun && state.selection.is_selected(day + Days::new(1)) {
547 let mut gap_area = state.area_days[day.day0() as usize];
548 gap_area.x += 2;
549 gap_area.width = 1;
550 Span::from(" ").style(day_style).render(gap_area, buf);
551 }
552
553 x += 3;
554 day = day + Days::new(1);
555 } else {
556 x += 3;
557 }
558 }
559
560 w += 1;
561 x = state.inner.x;
562 y += 1;
563 }
564}
565
566fn calc_day_style<Selection: CalendarSelection>(
567 widget: &Month<'_, Selection>,
568 state: &mut MonthState<Selection>,
569 day: NaiveDate,
570 day_style: Style,
571 select_style: Style,
572) -> Style {
573 let day_style = if let Some(day_styles) = widget.day_styles {
574 if let Some(day_style) = day_styles.get(&day) {
575 *day_style
576 } else {
577 day_style
578 }
579 } else {
580 day_style
581 };
582
583 if (state.is_container_focused() || state.is_focused())
584 && state.selection.lead_selection() == Some(day)
585 {
586 day_style.patch(select_style.underlined())
587 } else if state.selection.is_selected(day) {
588 day_style.patch(select_style)
589 } else {
590 day_style
591 }
592}
593
594impl<Selection> HasFocus for MonthState<Selection> {
595 fn build(&self, builder: &mut FocusBuilder) {
596 builder.leaf_widget(self);
597 }
598
599 #[inline]
600 fn focus(&self) -> FocusFlag {
601 self.focus.clone()
602 }
603
604 #[inline]
605 fn area(&self) -> Rect {
606 self.area
607 }
608}
609
610impl<Selection> HasScreenCursor for MonthState<Selection> {
611 fn screen_cursor(&self) -> Option<(u16, u16)> {
612 None
613 }
614}
615
616impl<Selection> RelocatableState for MonthState<Selection> {
617 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
618 self.area.relocate(shift, clip);
619 self.inner.relocate(shift, clip);
620 self.area_cal.relocate(shift, clip);
621 self.area_weeknum.relocate(shift, clip);
622 self.area_days.relocate(shift, clip);
623 self.area_weeks.relocate(shift, clip);
624 }
625}
626
627impl<Selection> Clone for MonthState<Selection>
628where
629 Selection: Clone,
630{
631 fn clone(&self) -> Self {
632 Self {
633 area: self.area,
634 inner: self.inner,
635 area_cal: self.area_cal.clone(),
636 area_days: self.area_days.clone(),
637 area_weeknum: self.area_weeknum.clone(),
638 area_weeks: self.area_weeks.clone(),
639 start_date: self.start_date,
640 selection: self.selection.clone(),
641 container: self.container.clone(),
642 focus: self.focus.new_instance(),
643 mouse: Default::default(),
644 non_exhaustive: NonExhaustive,
645 }
646 }
647}
648
649impl<Selection> Default for MonthState<Selection>
650where
651 Selection: Default,
652{
653 #[allow(deprecated)]
654 fn default() -> Self {
655 Self {
656 area: Default::default(),
657 inner: Default::default(),
658 area_cal: Default::default(),
659 area_days: Default::default(),
660 area_weeknum: Default::default(),
661 area_weeks: Default::default(),
662 start_date: Default::default(),
663 selection: Default::default(),
664 container: Default::default(),
665 focus: Default::default(),
666 mouse: Default::default(),
667 non_exhaustive: NonExhaustive,
668 }
669 }
670}
671
672impl<Selection> MonthState<Selection> {
673 pub fn new() -> Self
674 where
675 Selection: Default,
676 {
677 Self::default()
678 }
679
680 pub fn named(name: &str) -> Self
681 where
682 Selection: Default,
683 {
684 let mut z = Self::default();
685 z.focus = z.focus.with_name(name);
686 z
687 }
688
689 pub fn set_start_date(&mut self, date: NaiveDate) -> bool {
694 let old_value = self.start_date;
695 self.start_date = first_day_of_month(date);
696 old_value != self.start_date
697 }
698
699 pub fn start_date(&self) -> NaiveDate {
701 self.start_date
702 }
703
704 pub fn end_date(&self) -> NaiveDate {
706 last_day_of_month(self.start_date)
707 }
708
709 fn in_range(&self, date: NaiveDate) -> bool {
710 date >= self.start_date() && date <= self.end_date()
711 }
712
713 pub fn week_len(&self) -> usize {
715 Self::count_weeks(self.start_date)
716 }
717
718 pub fn count_weeks(day: NaiveDate) -> usize {
720 let mut day = day.with_day0(0).expect("date");
721 let month = day.month();
722
723 let mut weeks = 1;
724 for weekday in [
725 Weekday::Mon,
726 Weekday::Tue,
727 Weekday::Wed,
728 Weekday::Thu,
729 Weekday::Fri,
730 Weekday::Sat,
731 Weekday::Sun,
732 ] {
733 if day.weekday() == weekday {
735 day = day + Days::new(1);
736 }
737 }
738 while month == day.month() {
740 weeks += 1;
741 day = day + Days::new(7);
742 }
743
744 weeks
745 }
746
747 fn is_container_focused(&self) -> bool {
749 self.container
750 .as_ref()
751 .map(|v| v.is_focused())
752 .unwrap_or(false)
753 }
754
755 pub fn screen_cursor(&self) -> Option<(u16, u16)> {
757 None
758 }
759}
760
761impl<Selection> MonthState<Selection>
762where
763 Selection: CalendarSelection,
764{
765 pub fn lead_selection(&self) -> Option<NaiveDate> {
767 self.selection.lead_selection()
768 }
769}
770
771impl MonthState<NoSelection> {}
772
773impl MonthState<SingleSelection> {
774 pub fn clear_selection(&mut self) {
776 self.selection.borrow_mut().clear();
777 }
778
779 pub fn select_day(&mut self, n: usize) -> CalOutcome {
781 if let Some(date) = self.start_date.with_day0(n as u32) {
782 if self.selection.borrow_mut().select(date) {
783 CalOutcome::Selected
784 } else {
785 CalOutcome::Continue
786 }
787 } else {
788 CalOutcome::Continue
789 }
790 }
791
792 pub fn select_last(&mut self) -> CalOutcome {
794 let date = self.end_date();
795 if self.selection.borrow_mut().select(date) {
796 CalOutcome::Selected
797 } else {
798 CalOutcome::Continue
799 }
800 }
801
802 pub fn select_date(&mut self, d: NaiveDate) -> bool {
806 let start = self.start_date;
807 if d.year() == start.year() && d.month() == start.month() {
808 self.selection.borrow_mut().select(d)
809 } else {
810 false
811 }
812 }
813
814 pub fn selected_date(&self) -> Option<NaiveDate> {
816 self.selection.lead_selection()
817 }
818
819 pub fn prev_day(&mut self, n: usize) -> CalOutcome {
821 let base_start = self.start_date();
822 let base_end = self.end_date();
823
824 let date = if let Some(date) = self.selection.lead_selection() {
825 if date >= base_start && date <= base_end {
826 date - Days::new(n as u64)
827 } else if date < base_start {
828 self.start_date()
829 } else {
830 self.end_date()
831 }
832 } else {
833 self.end_date()
834 };
835
836 if self.in_range(date) {
837 if self.selection.borrow_mut().select(date) {
838 CalOutcome::Selected
839 } else {
840 CalOutcome::Continue
841 }
842 } else {
843 CalOutcome::Continue
844 }
845 }
846
847 pub fn next_day(&mut self, n: usize) -> CalOutcome {
849 let base_start = self.start_date();
850 let base_end = self.end_date();
851
852 let date = if let Some(date) = self.selection.lead_selection() {
853 if date >= base_start && date <= base_end {
854 date + Days::new(n as u64)
855 } else if date < base_start {
856 self.start_date()
857 } else {
858 self.end_date()
859 }
860 } else {
861 self.start_date()
862 };
863
864 if self.in_range(date) {
865 if self.selection.borrow_mut().select(date) {
866 CalOutcome::Selected
867 } else {
868 CalOutcome::Continue
869 }
870 } else {
871 CalOutcome::Continue
872 }
873 }
874}
875
876impl MonthState<RangeSelection> {
877 pub fn clear_selection(&mut self) {
879 self.selection.borrow_mut().clear();
880 }
881
882 pub fn select_week(&mut self, n: usize, extend: bool) -> CalOutcome {
884 if n < self.week_len() {
885 let date = self.start_date() + Days::new(7 * n as u64);
886 if self.selection.borrow_mut().select_week(date, extend) {
887 CalOutcome::Selected
888 } else {
889 CalOutcome::Continue
890 }
891 } else {
892 CalOutcome::Continue
893 }
894 }
895
896 pub fn select_day(&mut self, n: usize, extend: bool) -> CalOutcome {
898 if let Some(date) = self.start_date.with_day0(n as u32) {
899 if self.selection.borrow_mut().select_day(date, extend) {
900 CalOutcome::Selected
901 } else {
902 CalOutcome::Continue
903 }
904 } else {
905 CalOutcome::Continue
906 }
907 }
908
909 pub fn select_last(&mut self, extend: bool) -> CalOutcome {
911 let date = self.end_date();
912 if self.selection.borrow_mut().select_day(date, extend) {
913 CalOutcome::Selected
914 } else {
915 CalOutcome::Continue
916 }
917 }
918
919 pub fn select_week_by_date(&mut self, date: NaiveDate, extend: bool) -> bool {
923 let base = self.start_date;
924
925 let start = date.week(Weekday::Mon).first_day();
926 let end = date.week(Weekday::Mon).last_day();
927
928 if (start.year() == base.year() && start.month() == base.month())
929 || (end.year() == base.year() && end.month() == base.month())
930 {
931 self.selection.borrow_mut().select_week(start, extend)
932 } else {
933 false
934 }
935 }
936
937 pub fn select_date(&mut self, d: NaiveDate, extend: bool) -> bool {
941 let base = self.start_date;
942 if d.year() == base.year() && d.month() == base.month() {
943 self.selection.borrow_mut().select_day(d, extend)
944 } else {
945 false
946 }
947 }
948
949 pub fn selected_date(&self) -> Option<NaiveDate> {
951 self.selection.lead_selection()
952 }
953
954 pub fn prev_day(&mut self, n: usize, extend: bool) -> CalOutcome {
956 let base_start = self.start_date();
957 let base_end = self.end_date();
958
959 let date = if let Some(date) = self.selection.lead_selection() {
960 if date >= base_start && date <= base_end {
961 date - Days::new(n as u64)
962 } else if date < base_start {
963 self.start_date()
964 } else {
965 self.end_date()
966 }
967 } else {
968 self.end_date()
969 };
970
971 if self.in_range(date) {
972 if self.selection.borrow_mut().select_day(date, extend) {
973 CalOutcome::Selected
974 } else {
975 CalOutcome::Continue
976 }
977 } else {
978 CalOutcome::Continue
979 }
980 }
981
982 pub fn next_day(&mut self, n: usize, extend: bool) -> CalOutcome {
984 let base_start = self.start_date();
985 let base_end = self.end_date();
986
987 let date = if let Some(date) = self.selection.lead_selection() {
988 if date >= base_start && date <= base_end {
989 date + Days::new(n as u64)
990 } else if date < base_start {
991 self.start_date()
992 } else {
993 self.end_date()
994 }
995 } else {
996 self.start_date()
997 };
998
999 if self.in_range(date) {
1000 if self.selection.borrow_mut().select_day(date, extend) {
1001 CalOutcome::Selected
1002 } else {
1003 CalOutcome::Continue
1004 }
1005 } else {
1006 CalOutcome::Continue
1007 }
1008 }
1009
1010 pub fn prev_week(&mut self, n: usize, extend: bool) -> CalOutcome {
1012 let base_start = self.start_date();
1013 let base_end = self.end_date();
1014
1015 if let Some(date) = self.selection.lead_selection() {
1016 let new_date = if date >= base_start && date <= base_end {
1017 date - Days::new(7 * n as u64)
1018 } else if date < base_start {
1019 self.start_date()
1020 } else {
1021 self.end_date()
1022 };
1023 let new_date_end = new_date.week(Weekday::Mon).last_day();
1024 if new_date_end >= base_start && new_date_end <= base_end {
1025 if self.selection.borrow_mut().select_week(new_date, extend) {
1026 CalOutcome::Selected
1027 } else {
1028 CalOutcome::Continue
1029 }
1030 } else {
1031 CalOutcome::Continue
1032 }
1033 } else {
1034 let new_date = self.end_date();
1035 if self.selection.borrow_mut().select_week(new_date, extend) {
1036 CalOutcome::Selected
1037 } else {
1038 CalOutcome::Continue
1039 }
1040 }
1041 }
1042
1043 pub fn next_week(&mut self, n: usize, extend: bool) -> CalOutcome {
1045 let start = self.start_date();
1046 let end = self.end_date();
1047
1048 let new_date = if let Some(date) = self.selection.lead_selection() {
1049 let date_end = date.week(Weekday::Mon).last_day();
1050 if date_end >= start && date_end <= end {
1051 date + Days::new(7 * n as u64)
1052 } else if date_end < start {
1053 self.start_date()
1054 } else {
1055 self.end_date()
1056 }
1057 } else {
1058 self.start_date()
1059 };
1060
1061 if new_date >= start && new_date <= end {
1062 if self.selection.borrow_mut().select_week(new_date, extend) {
1063 CalOutcome::Selected
1064 } else {
1065 CalOutcome::Continue
1066 }
1067 } else {
1068 CalOutcome::Continue
1069 }
1070 }
1071}