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