1use crate::_private::NonExhaustive;
2use crate::calendar::event::CalOutcome;
3use crate::calendar::selection::{NoSelection, RangeSelection, SingleSelection};
4use crate::calendar::style::CalendarStyle;
5use crate::calendar::{first_day_of_month, last_day_of_month, CalendarSelection};
6use crate::util::{block_size, revert_style};
7use chrono::{Datelike, Days, NaiveDate, Weekday};
8use rat_event::util::MouseFlagsN;
9use rat_focus::{FocusBuilder, FocusFlag, HasFocus};
10use rat_reloc::RelocatableState;
11use ratatui::buffer::Buffer;
12use ratatui::layout::{Alignment, Rect};
13use ratatui::prelude::Style;
14use ratatui::style::Stylize;
15use ratatui::text::Span;
16use ratatui::widgets::block::Title;
17#[cfg(feature = "unstable-widget-ref")]
18use ratatui::widgets::StatefulWidgetRef;
19use ratatui::widgets::{Block, StatefulWidget, Widget};
20use std::cell::RefCell;
21use std::cmp::max;
22use std::collections::HashMap;
23use std::marker::PhantomData;
24use std::rc::Rc;
25
26#[derive(Debug, Clone)]
55pub struct Month<'a, Selection> {
56 start_date: Option<NaiveDate>,
58
59 style: Style,
61 title_style: Option<Style>,
63 title_align: Alignment,
65 weeknum_style: Option<Style>,
67 weekday_style: Option<Style>,
69 day_style: Option<Style>,
71 day_styles: Option<&'a HashMap<NaiveDate, Style>>,
73 select_style: Option<Style>,
75 focus_style: Option<Style>,
77
78 show_month: bool,
80 show_weekdays: bool,
82
83 block: Option<Block<'a>>,
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 show_month: true,
149 show_weekdays: true,
150 block: Default::default(),
151 loc: Default::default(),
152 phantom: PhantomData,
153 }
154 }
155}
156
157impl<'a, Selection> Month<'a, Selection> {
158 pub fn new() -> Self {
160 Self::default()
161 }
162
163 #[inline]
166 pub fn date(mut self, s: NaiveDate) -> Self {
167 self.start_date = Some(first_day_of_month(s));
168 self
169 }
170
171 #[inline]
173 pub fn locale(mut self, loc: chrono::Locale) -> Self {
174 self.loc = loc;
175 self
176 }
177
178 #[inline]
180 pub fn show_show_month(mut self) -> Self {
181 self.show_month = true;
182 self
183 }
184
185 #[inline]
187 pub fn show_weekdays(mut self) -> Self {
188 self.show_weekdays = true;
189 self
190 }
191
192 #[inline]
194 pub fn styles(mut self, s: CalendarStyle) -> Self {
195 self.style = s.style;
196 if s.title.is_some() {
197 self.title_style = s.title;
198 }
199 if s.weeknum.is_some() {
200 self.weeknum_style = s.weeknum;
201 }
202 if s.weekday.is_some() {
203 self.weekday_style = s.weekday;
204 }
205 if s.day.is_some() {
206 self.day_style = s.day;
207 }
208 if s.select.is_some() {
209 self.select_style = s.select;
210 }
211 if s.focus.is_some() {
212 self.focus_style = s.focus;
213 }
214 if s.block.is_some() {
215 self.block = s.block;
216 }
217 self.block = self.block.map(|v| v.style(self.style));
218 self
219 }
220
221 pub fn select_style(mut self, style: Style) -> Self {
223 self.select_style = Some(style);
224 self
225 }
226
227 pub fn focus_style(mut self, style: Style) -> Self {
229 self.focus_style = Some(style);
230 self
231 }
232
233 #[inline]
235 pub fn day_style(mut self, s: impl Into<Style>) -> Self {
236 self.day_style = Some(s.into());
237 self
238 }
239
240 #[inline]
242 pub fn day_styles(mut self, styles: &'a HashMap<NaiveDate, Style>) -> Self {
243 self.day_styles = Some(styles);
244 self
245 }
246
247 #[inline]
249 pub fn week_style(mut self, s: impl Into<Style>) -> Self {
250 self.weeknum_style = Some(s.into());
251 self
252 }
253
254 #[inline]
256 pub fn weekday_style(mut self, s: impl Into<Style>) -> Self {
257 self.weekday_style = Some(s.into());
258 self
259 }
260
261 #[inline]
263 pub fn title_style(mut self, s: impl Into<Style>) -> Self {
264 self.title_style = Some(s.into());
265 self
266 }
267
268 #[inline]
270 pub fn title_align(mut self, a: Alignment) -> Self {
271 self.title_align = a;
272 self
273 }
274
275 #[inline]
277 pub fn block(mut self, b: Block<'a>) -> Self {
278 self.block = Some(b);
279 self.block = self.block.map(|v| v.style(self.style));
280 self
281 }
282
283 #[inline]
285 pub fn width(&self) -> u16 {
286 8 * 3 + block_size(&self.block).width
287 }
288
289 #[inline]
292 pub fn height(&self, state: &MonthState<Selection>) -> u16 {
293 let start_date = if let Some(start_date) = self.start_date {
294 start_date
295 } else {
296 state.start_date
297 };
298
299 let r = MonthState::<Selection>::count_weeks(start_date) as u16;
300 let w = if self.show_weekdays { 1 } else { 0 };
301 let b = max(1, block_size(&self.block).height);
302 r + w + b
303 }
304}
305
306#[cfg(feature = "unstable-widget-ref")]
307impl<'a, Selection> StatefulWidgetRef for Month<'a, Selection>
308where
309 Selection: CalendarSelection,
310{
311 type State = MonthState<Selection>;
312
313 fn render_ref(&self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
314 render_ref(self, area, buf, state);
315 }
316}
317
318impl<Selection> StatefulWidget for Month<'_, Selection>
319where
320 Selection: CalendarSelection,
321{
322 type State = MonthState<Selection>;
323
324 fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
325 render_ref(&self, area, buf, state);
326 }
327}
328
329fn render_ref<Selection: CalendarSelection>(
330 widget: &Month<'_, Selection>,
331 area: Rect,
332 buf: &mut Buffer,
333 state: &mut MonthState<Selection>,
334) {
335 state.area = area;
336 if let Some(start_date) = widget.start_date {
337 state.start_date = start_date;
338 }
339
340 let mut day = state.start_date;
341
342 let focus_style = widget.focus_style.unwrap_or(revert_style(widget.style));
343 let select_style = if let Some(select_style) = widget.select_style {
344 if state.is_container_focused() || state.is_focused() {
345 focus_style
346 } else {
347 select_style
348 }
349 } else {
350 if state.is_container_focused() || state.is_focused() {
351 focus_style
352 } else {
353 revert_style(widget.style)
354 }
355 };
356 let day_style = widget.day_style.unwrap_or(widget.style);
357 let week_style = widget.weeknum_style.unwrap_or(widget.style);
358 let weekday_style = widget.weekday_style.unwrap_or(widget.style);
359
360 let title_style = if let Some(title_style) = widget.title_style {
361 title_style
362 } else {
363 widget.style
364 };
365 let title_style = if state.is_focused() {
366 title_style.patch(focus_style)
367 } else {
368 title_style
369 };
370
371 let block = if widget.show_month {
372 if let Some(block) = widget.block.clone() {
373 block
374 .title(Title::from(
375 day.format_localized("%B", widget.loc).to_string(),
376 ))
377 .title_style(title_style)
378 .title_alignment(widget.title_align)
379 } else {
380 Block::new()
381 .style(widget.style)
382 .title(Title::from(
383 day.format_localized("%B", widget.loc).to_string(),
384 ))
385 .title_style(title_style)
386 .title_alignment(widget.title_align)
387 }
388 } else {
389 if let Some(block) = widget.block.clone() {
390 block
391 } else {
392 Block::new().style(widget.style)
393 }
394 };
395 state.inner = block.inner(area);
396 block.render(area, buf);
397
398 let month = day.month();
399 let mut w = 0;
400 let mut x = state.inner.x;
401 let mut y = state.inner.y;
402
403 if widget.show_weekdays {
405 let mut week_0 = day.week(Weekday::Mon).first_day();
406
407 x += 3;
408 buf.set_style(Rect::new(x, y, 3 * 7, 1), weekday_style);
409 for _ in 0..7 {
410 let area = Rect::new(x, y, 2, 1).intersection(state.inner);
411
412 let day_name = week_0.format_localized("%a", widget.loc).to_string();
413 Span::from(format!("{:2} ", day_name)).render(area, buf);
414
415 x += 3;
416 week_0 = week_0 + Days::new(1);
417 }
418 x = state.inner.x;
419 y += 1;
420 }
421
422 for i in 0..31 {
424 state.area_days[i] = Rect::default();
425 }
426 for i in 0..6 {
427 state.area_weeks[i] = Rect::default();
428 }
429 state.area_cal = Rect::new(x + 3, y, 7 * 3, state.week_len() as u16);
430 state.area_weeknum = Rect::new(x, y, 3, state.week_len() as u16);
431
432 state.area_weeks[w] = Rect::new(x, y, 2, 1).intersection(state.inner);
434 Span::from(day.format_localized("%V", widget.loc).to_string())
435 .style(week_style)
436 .render(state.area_weeks[w], buf);
437
438 x += 3;
439
440 for wd in [
441 Weekday::Mon,
442 Weekday::Tue,
443 Weekday::Wed,
444 Weekday::Thu,
445 Weekday::Fri,
446 Weekday::Sat,
447 Weekday::Sun,
448 ] {
449 if day.weekday() != wd {
450 x += 3;
451 } else {
452 let day_style = calc_day_style(widget, state, day, day_style, select_style);
453 state.area_days[day.day0() as usize] = Rect::new(x, y, 2, 1).intersection(state.inner);
454
455 Span::from(day.format_localized("%e", widget.loc).to_string())
456 .style(day_style)
457 .render(state.area_days[day.day0() as usize], buf);
458
459 if wd != Weekday::Sun && state.selection.is_selected(day + Days::new(1)) {
460 let mut gap_area = state.area_days[day.day0() as usize];
461 gap_area.x += 2;
462 gap_area.width = 1;
463 Span::from(" ").style(day_style).render(gap_area, buf);
464 }
465
466 x += 3;
467 day = day + Days::new(1);
468 }
469 }
470
471 w += 1;
472 x = state.inner.x;
473 y += 1;
474
475 while month == day.month() {
476 state.area_weeks[w] = Rect::new(x, y, 2, 1).intersection(state.inner);
477 Span::from(day.format_localized("%V", widget.loc).to_string())
478 .style(week_style)
479 .render(state.area_weeks[w], buf);
480
481 x += 3;
482
483 for wd in [
484 Weekday::Mon,
485 Weekday::Tue,
486 Weekday::Wed,
487 Weekday::Thu,
488 Weekday::Fri,
489 Weekday::Sat,
490 Weekday::Sun,
491 ] {
492 if day.month() == month {
493 let day_style = calc_day_style(widget, state, day, day_style, select_style);
494
495 state.area_days[day.day0() as usize] =
496 Rect::new(x, y, 2, 1).intersection(state.inner);
497
498 Span::from(day.format_localized("%e", widget.loc).to_string())
499 .style(day_style)
500 .render(state.area_days[day.day0() as usize], buf);
501
502 if wd != Weekday::Sun && state.selection.is_selected(day + Days::new(1)) {
503 let mut gap_area = state.area_days[day.day0() as usize];
504 gap_area.x += 2;
505 gap_area.width = 1;
506 Span::from(" ").style(day_style).render(gap_area, buf);
507 }
508
509 x += 3;
510 day = day + Days::new(1);
511 } else {
512 x += 3;
513 }
514 }
515
516 w += 1;
517 x = state.inner.x;
518 y += 1;
519 }
520}
521
522fn calc_day_style<Selection: CalendarSelection>(
523 widget: &Month<'_, Selection>,
524 state: &mut MonthState<Selection>,
525 day: NaiveDate,
526 day_style: Style,
527 select_style: Style,
528) -> Style {
529 let day_style = if let Some(day_styles) = widget.day_styles {
530 if let Some(day_style) = day_styles.get(&day) {
531 *day_style
532 } else {
533 day_style
534 }
535 } else {
536 day_style
537 };
538
539 if (state.is_container_focused() || state.is_focused())
540 && state.selection.lead_selection() == Some(day)
541 {
542 day_style.patch(select_style.underlined())
543 } else if state.selection.is_selected(day) {
544 day_style.patch(select_style)
545 } else {
546 day_style
547 }
548}
549
550impl<Selection> HasFocus for MonthState<Selection> {
551 fn build(&self, builder: &mut FocusBuilder) {
552 builder.leaf_widget(self);
553 }
554
555 #[inline]
556 fn focus(&self) -> FocusFlag {
557 self.focus.clone()
558 }
559
560 #[inline]
561 fn area(&self) -> Rect {
562 self.area
563 }
564}
565
566impl<Selection> RelocatableState for MonthState<Selection> {
567 fn relocate(&mut self, shift: (i16, i16), clip: Rect) {
568 self.area.relocate(shift, clip);
569 self.inner.relocate(shift, clip);
570 self.area_cal.relocate(shift, clip);
571 self.area_weeknum.relocate(shift, clip);
572 self.area_days.relocate(shift, clip);
573 self.area_weeks.relocate(shift, clip);
574 }
575}
576
577impl<Selection> Clone for MonthState<Selection>
578where
579 Selection: Clone,
580{
581 fn clone(&self) -> Self {
582 Self {
583 area: self.area,
584 inner: self.inner,
585 area_cal: self.area_cal.clone(),
586 area_days: self.area_days.clone(),
587 area_weeknum: self.area_weeknum.clone(),
588 area_weeks: self.area_weeks.clone(),
589 start_date: self.start_date,
590 selection: self.selection.clone(),
591 container: self.container.clone(),
592 focus: FocusFlag::named(self.focus.name()),
593 mouse: Default::default(),
594 non_exhaustive: NonExhaustive,
595 }
596 }
597}
598
599impl<Selection> Default for MonthState<Selection>
600where
601 Selection: Default,
602{
603 fn default() -> Self {
604 Self {
605 area: Default::default(),
606 inner: Default::default(),
607 area_cal: Default::default(),
608 area_days: Default::default(),
609 area_weeknum: Default::default(),
610 area_weeks: Default::default(),
611 start_date: Default::default(),
612 selection: Default::default(),
613 container: Default::default(),
614 focus: Default::default(),
615 mouse: Default::default(),
616 non_exhaustive: NonExhaustive,
617 }
618 }
619}
620
621impl<Selection> MonthState<Selection> {
622 pub fn new() -> Self
623 where
624 Selection: Default,
625 {
626 Self::default()
627 }
628
629 pub fn named(name: &str) -> Self
630 where
631 Selection: Default,
632 {
633 Self {
634 focus: FocusFlag::named(name),
635 ..Self::default()
636 }
637 }
638
639 pub fn set_start_date(&mut self, date: NaiveDate) -> bool {
644 let old_value = self.start_date;
645 self.start_date = first_day_of_month(date);
646 old_value != self.start_date
647 }
648
649 pub fn start_date(&self) -> NaiveDate {
651 self.start_date
652 }
653
654 pub fn end_date(&self) -> NaiveDate {
656 last_day_of_month(self.start_date)
657 }
658
659 fn in_range(&self, date: NaiveDate) -> bool {
660 date >= self.start_date() && date <= self.end_date()
661 }
662
663 pub fn week_len(&self) -> usize {
665 Self::count_weeks(self.start_date)
666 }
667
668 pub fn count_weeks(day: NaiveDate) -> usize {
670 let mut day = day.with_day0(0).expect("date");
671 let month = day.month();
672
673 let mut weeks = 1;
674 for weekday in [
675 Weekday::Mon,
676 Weekday::Tue,
677 Weekday::Wed,
678 Weekday::Thu,
679 Weekday::Fri,
680 Weekday::Sat,
681 Weekday::Sun,
682 ] {
683 if day.weekday() == weekday {
685 day = day + Days::new(1);
686 }
687 }
688 while month == day.month() {
690 weeks += 1;
691 day = day + Days::new(7);
692 }
693
694 weeks
695 }
696
697 fn is_container_focused(&self) -> bool {
699 self.container
700 .as_ref()
701 .map(|v| v.is_focused())
702 .unwrap_or(false)
703 }
704}
705
706impl<Selection> MonthState<Selection>
707where
708 Selection: CalendarSelection,
709{
710 pub fn lead_selection(&self) -> Option<NaiveDate> {
712 self.selection.lead_selection()
713 }
714}
715
716impl MonthState<NoSelection> {}
717
718impl MonthState<SingleSelection> {
719 pub fn clear_selection(&mut self) {
721 self.selection.borrow_mut().clear();
722 }
723
724 pub fn select_day(&mut self, n: usize) -> CalOutcome {
726 if let Some(date) = self.start_date.with_day0(n as u32) {
727 if self.selection.borrow_mut().select(date) {
728 CalOutcome::Selected
729 } else {
730 CalOutcome::Continue
731 }
732 } else {
733 CalOutcome::Continue
734 }
735 }
736
737 pub fn select_last(&mut self) -> CalOutcome {
739 let date = self.end_date();
740 if self.selection.borrow_mut().select(date) {
741 CalOutcome::Selected
742 } else {
743 CalOutcome::Continue
744 }
745 }
746
747 pub fn select_date(&mut self, d: NaiveDate) -> bool {
751 let start = self.start_date;
752 if d.year() == start.year() && d.month() == start.month() {
753 self.selection.borrow_mut().select(d)
754 } else {
755 false
756 }
757 }
758
759 pub fn selected_date(&self) -> Option<NaiveDate> {
761 self.selection.lead_selection()
762 }
763
764 pub fn prev_day(&mut self, n: usize) -> CalOutcome {
766 let base_start = self.start_date();
767 let base_end = self.end_date();
768
769 let date = if let Some(date) = self.selection.lead_selection() {
770 if date >= base_start && date <= base_end {
771 date - Days::new(n as u64)
772 } else if date < base_start {
773 self.start_date()
774 } else {
775 self.end_date()
776 }
777 } else {
778 self.end_date()
779 };
780
781 if self.in_range(date) {
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 next_day(&mut self, n: usize) -> CalOutcome {
794 let base_start = self.start_date();
795 let base_end = self.end_date();
796
797 let date = if let Some(date) = self.selection.lead_selection() {
798 if date >= base_start && date <= base_end {
799 date + Days::new(n as u64)
800 } else if date < base_start {
801 self.start_date()
802 } else {
803 self.end_date()
804 }
805 } else {
806 self.start_date()
807 };
808
809 if self.in_range(date) {
810 if self.selection.borrow_mut().select(date) {
811 CalOutcome::Selected
812 } else {
813 CalOutcome::Continue
814 }
815 } else {
816 CalOutcome::Continue
817 }
818 }
819}
820
821impl MonthState<RangeSelection> {
822 pub fn clear_selection(&mut self) {
824 self.selection.borrow_mut().clear();
825 }
826
827 pub fn select_week(&mut self, n: usize, extend: bool) -> CalOutcome {
829 if n < self.week_len() {
830 let date = self.start_date() + Days::new(7 * n as u64);
831 if self.selection.borrow_mut().select_week(date, extend) {
832 CalOutcome::Selected
833 } else {
834 CalOutcome::Continue
835 }
836 } else {
837 CalOutcome::Continue
838 }
839 }
840
841 pub fn select_day(&mut self, n: usize, extend: bool) -> CalOutcome {
843 if let Some(date) = self.start_date.with_day0(n as u32) {
844 if self.selection.borrow_mut().select_day(date, extend) {
845 CalOutcome::Selected
846 } else {
847 CalOutcome::Continue
848 }
849 } else {
850 CalOutcome::Continue
851 }
852 }
853
854 pub fn select_last(&mut self, extend: bool) -> CalOutcome {
856 let date = self.end_date();
857 if self.selection.borrow_mut().select_day(date, extend) {
858 CalOutcome::Selected
859 } else {
860 CalOutcome::Continue
861 }
862 }
863
864 pub fn select_week_by_date(&mut self, date: NaiveDate, extend: bool) -> bool {
868 let base = self.start_date;
869
870 let start = date.week(Weekday::Mon).first_day();
871 let end = date.week(Weekday::Mon).last_day();
872
873 if (start.year() == base.year() && start.month() == base.month())
874 || (end.year() == base.year() && end.month() == base.month())
875 {
876 self.selection.borrow_mut().select_week(start, extend)
877 } else {
878 false
879 }
880 }
881
882 pub fn select_date(&mut self, d: NaiveDate, extend: bool) -> bool {
886 let base = self.start_date;
887 if d.year() == base.year() && d.month() == base.month() {
888 self.selection.borrow_mut().select_day(d, extend)
889 } else {
890 false
891 }
892 }
893
894 pub fn selected_date(&self) -> Option<NaiveDate> {
896 self.selection.lead_selection()
897 }
898
899 pub fn prev_day(&mut self, n: usize, extend: bool) -> CalOutcome {
901 let base_start = self.start_date();
902 let base_end = self.end_date();
903
904 let date = if let Some(date) = self.selection.lead_selection() {
905 if date >= base_start && date <= base_end {
906 date - Days::new(n as u64)
907 } else if date < base_start {
908 self.start_date()
909 } else {
910 self.end_date()
911 }
912 } else {
913 self.end_date()
914 };
915
916 if self.in_range(date) {
917 if self.selection.borrow_mut().select_day(date, extend) {
918 CalOutcome::Selected
919 } else {
920 CalOutcome::Continue
921 }
922 } else {
923 CalOutcome::Continue
924 }
925 }
926
927 pub fn next_day(&mut self, n: usize, extend: bool) -> CalOutcome {
929 let base_start = self.start_date();
930 let base_end = self.end_date();
931
932 let date = if let Some(date) = self.selection.lead_selection() {
933 if date >= base_start && date <= base_end {
934 date + Days::new(n as u64)
935 } else if date < base_start {
936 self.start_date()
937 } else {
938 self.end_date()
939 }
940 } else {
941 self.start_date()
942 };
943
944 if self.in_range(date) {
945 if self.selection.borrow_mut().select_day(date, extend) {
946 CalOutcome::Selected
947 } else {
948 CalOutcome::Continue
949 }
950 } else {
951 CalOutcome::Continue
952 }
953 }
954
955 pub fn prev_week(&mut self, n: usize, extend: bool) -> CalOutcome {
957 let base_start = self.start_date();
958 let base_end = self.end_date();
959
960 if let Some(date) = self.selection.lead_selection() {
961 let new_date = if date >= base_start && date <= base_end {
962 date - Days::new(7 * n as u64)
963 } else if date < base_start {
964 self.start_date()
965 } else {
966 self.end_date()
967 };
968 let new_date_end = new_date.week(Weekday::Mon).last_day();
969 if new_date_end >= base_start && new_date_end <= base_end {
970 if self.selection.borrow_mut().select_week(new_date, extend) {
971 CalOutcome::Selected
972 } else {
973 CalOutcome::Continue
974 }
975 } else {
976 CalOutcome::Continue
977 }
978 } else {
979 let new_date = self.end_date();
980 if self.selection.borrow_mut().select_week(new_date, extend) {
981 CalOutcome::Selected
982 } else {
983 CalOutcome::Continue
984 }
985 }
986 }
987
988 pub fn next_week(&mut self, n: usize, extend: bool) -> CalOutcome {
990 let start = self.start_date();
991 let end = self.end_date();
992
993 let new_date = if let Some(date) = self.selection.lead_selection() {
994 let date_end = date.week(Weekday::Mon).last_day();
995 if date_end >= start && date_end <= end {
996 date + Days::new(7 * n as u64)
997 } else if date_end < start {
998 self.start_date()
999 } else {
1000 self.end_date()
1001 }
1002 } else {
1003 self.start_date()
1004 };
1005
1006 if new_date >= start && new_date <= end {
1007 if self.selection.borrow_mut().select_week(new_date, extend) {
1008 CalOutcome::Selected
1009 } else {
1010 CalOutcome::Continue
1011 }
1012 } else {
1013 CalOutcome::Continue
1014 }
1015 }
1016}