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