rat_widget/calendar/
single_selection.rs1use crate::calendar::event::CalOutcome;
2use crate::calendar::{CalendarSelection, CalendarState, MonthState};
3use chrono::NaiveDate;
4use rat_event::util::item_at;
5use rat_event::{ConsumedEvent, HandleEvent, MouseOnly, Regular, ct_event, flow};
6use rat_focus::HasFocus;
7
8#[derive(Debug, Default, Clone)]
14pub struct SingleSelection {
15 selected: Option<NaiveDate>,
16}
17
18impl CalendarSelection for SingleSelection {
19 fn count(&self) -> usize {
20 if self.selected.is_some() { 1 } else { 0 }
21 }
22
23 fn is_selected(&self, date: NaiveDate) -> bool {
24 self.selected == Some(date)
25 }
26
27 fn lead_selection(&self) -> Option<NaiveDate> {
28 self.selected
29 }
30}
31
32impl SingleSelection {
33 pub fn clear(&mut self) {
34 self.selected = None;
35 }
36
37 pub fn select(&mut self, date: NaiveDate) -> bool {
38 let old = self.selected;
39 self.selected = Some(date);
40 old != self.selected
41 }
42
43 pub fn selected(&self) -> Option<NaiveDate> {
44 self.selected
45 }
46}
47
48impl HandleEvent<crossterm::event::Event, Regular, CalOutcome> for MonthState<SingleSelection> {
49 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: Regular) -> CalOutcome {
50 if self.is_focused() {
51 flow!(match event {
52 ct_event!(keycode press Home) => self.select_day(0),
53 ct_event!(keycode press End) => self.select_last(),
54 ct_event!(keycode press Up) => self.prev_day(7),
55 ct_event!(keycode press Down) => self.next_day(7),
56 ct_event!(keycode press Left) => self.prev_day(1),
57 ct_event!(keycode press Right) => self.next_day(1),
58 _ => CalOutcome::Continue,
59 })
60 }
61
62 self.handle(event, MouseOnly)
63 }
64}
65
66impl HandleEvent<crossterm::event::Event, MouseOnly, CalOutcome> for MonthState<SingleSelection> {
67 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: MouseOnly) -> CalOutcome {
68 match event {
69 ct_event!(mouse drag Left for x, y) | ct_event!(mouse down Left for x, y) => {
70 if let Some(sel) = item_at(&self.area_days, *x, *y) {
71 self.select_day(sel)
72 } else {
73 CalOutcome::Continue
74 }
75 }
76
77 _ => CalOutcome::Continue,
78 }
79 }
80}
81
82impl<const N: usize> HandleEvent<crossterm::event::Event, Regular, CalOutcome>
83 for CalendarState<N, SingleSelection>
84{
85 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: Regular) -> CalOutcome {
86 let mut r = 'f: {
87 for month in &mut self.months {
88 let r = month.handle(event, Regular);
89 if r.is_consumed() {
90 self.focus_lead();
91 break 'f r;
92 }
93 }
94 CalOutcome::Continue
95 };
96
97 r = r.or_else(|| {
98 if self.is_focused() {
99 match event {
100 ct_event!(keycode press CONTROL-Home) => self.move_to_today(),
101 ct_event!(keycode press PageUp) => self.prev_month(1),
102 ct_event!(keycode press PageDown) => self.next_month(1),
103 ct_event!(keycode press Up) => self.prev_day(7),
104 ct_event!(keycode press Down) => self.next_day(7),
105 ct_event!(keycode press Left) => self.prev_day(1),
106 ct_event!(keycode press Right) => self.next_day(1),
107
108 _ => CalOutcome::Continue,
109 }
110 } else {
111 CalOutcome::Continue
112 }
113 });
114
115 r.or_else(|| self.handle(event, MouseOnly))
116 }
117}
118
119impl<const N: usize> HandleEvent<crossterm::event::Event, MouseOnly, CalOutcome>
120 for CalendarState<N, SingleSelection>
121{
122 fn handle(&mut self, event: &crossterm::event::Event, _qualifier: MouseOnly) -> CalOutcome {
123 for i in 0..self.months.len() {
124 if self.months[i].gained_focus() {
125 self.set_primary_idx(i);
126 break;
127 }
128 }
129
130 let all_areas = self
131 .months
132 .iter()
133 .map(|v| v.area)
134 .reduce(|v, w| v.union(w))
135 .unwrap_or_default();
136 match event {
137 ct_event!(scroll up for x,y) if all_areas.contains((*x, *y).into()) => {
138 self.scroll_back(self.step())
139 }
140 ct_event!(scroll down for x,y) if all_areas.contains((*x, *y).into()) => {
141 self.scroll_forward(self.step())
142 }
143 _ => CalOutcome::Continue,
144 }
145 }
146}