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