Skip to main content

rat_ftable/
noselection.rs

1use crate::event::TableOutcome;
2use crate::{TableSelection, TableState};
3use rat_event::{ConsumedEvent, HandleEvent, MouseOnly, Regular, ct_event};
4use rat_focus::HasFocus;
5use rat_scrolled::ScrollAreaState;
6use rat_scrolled::event::ScrollOutcome;
7use ratatui_crossterm::crossterm::event::Event;
8use std::cmp::max;
9
10/// Doesn't do any selection for the table.
11///
12/// But it implements scrolling via mouse and keyboard.
13#[derive(Debug, Default, Clone)]
14pub struct NoSelection;
15
16impl TableSelection for NoSelection {
17    fn count(&self) -> usize {
18        0
19    }
20
21    fn is_selected_row(&self, _row: usize) -> bool {
22        false
23    }
24
25    fn is_selected_column(&self, _column: usize) -> bool {
26        false
27    }
28
29    fn is_selected_cell(&self, _column: usize, _row: usize) -> bool {
30        false
31    }
32
33    fn lead_selection(&self) -> Option<(usize, usize)> {
34        None
35    }
36
37    fn validate_rows(&mut self, _rows: usize) {}
38
39    fn validate_cols(&mut self, _cols: usize) {}
40
41    fn items_added(&mut self, _pos: usize, _n: usize) {}
42
43    fn items_removed(&mut self, _pos: usize, _n: usize, _rows: usize) {}
44}
45
46impl HandleEvent<Event, Regular, TableOutcome> for TableState<NoSelection> {
47    fn handle(&mut self, event: &Event, _keymap: Regular) -> TableOutcome {
48        let res = if self.is_focused() {
49            match event {
50                ct_event!(keycode press Up) => {
51                    if self.scroll_up(1) {
52                        TableOutcome::Changed
53                    } else {
54                        TableOutcome::Unchanged
55                    }
56                }
57                ct_event!(keycode press Down) => {
58                    if self.scroll_down(1) {
59                        TableOutcome::Changed
60                    } else {
61                        TableOutcome::Unchanged
62                    }
63                }
64                ct_event!(keycode press CONTROL-Up)
65                | ct_event!(keycode press CONTROL-Home)
66                | ct_event!(keycode press Home) => {
67                    if self.scroll_to_row(0) {
68                        TableOutcome::Changed
69                    } else {
70                        TableOutcome::Unchanged
71                    }
72                }
73                ct_event!(keycode press CONTROL-Down)
74                | ct_event!(keycode press CONTROL-End)
75                | ct_event!(keycode press End) => {
76                    if self.scroll_to_row(self.rows.saturating_sub(1)) {
77                        TableOutcome::Changed
78                    } else {
79                        TableOutcome::Unchanged
80                    }
81                }
82                ct_event!(keycode press PageUp) => {
83                    if self.scroll_up(max(1, self.page_len().saturating_sub(1))) {
84                        TableOutcome::Changed
85                    } else {
86                        TableOutcome::Unchanged
87                    }
88                }
89                ct_event!(keycode press PageDown) => {
90                    if self.scroll_down(max(1, self.page_len().saturating_sub(1))) {
91                        TableOutcome::Changed
92                    } else {
93                        TableOutcome::Unchanged
94                    }
95                }
96                ct_event!(keycode press Left) => {
97                    if self.scroll_left(1) {
98                        TableOutcome::Changed
99                    } else {
100                        TableOutcome::Unchanged
101                    }
102                }
103                ct_event!(keycode press Right) => {
104                    if self.scroll_right(1) {
105                        TableOutcome::Changed
106                    } else {
107                        TableOutcome::Unchanged
108                    }
109                }
110                ct_event!(keycode press CONTROL-Left) => {
111                    if self.scroll_to_x(0) {
112                        TableOutcome::Changed
113                    } else {
114                        TableOutcome::Unchanged
115                    }
116                }
117                ct_event!(keycode press CONTROL-Right) => {
118                    if self.scroll_to_x(self.x_max_offset()) {
119                        TableOutcome::Changed
120                    } else {
121                        TableOutcome::Unchanged
122                    }
123                }
124                _ => TableOutcome::Continue,
125            }
126        } else {
127            TableOutcome::Continue
128        };
129
130        if res == TableOutcome::Continue {
131            self.handle(event, MouseOnly)
132        } else {
133            res
134        }
135    }
136}
137
138impl HandleEvent<Event, MouseOnly, TableOutcome> for TableState<NoSelection> {
139    fn handle(&mut self, event: &Event, _keymap: MouseOnly) -> TableOutcome {
140        if self.is_obscured() {
141            return TableOutcome::Continue;
142        }
143
144        let mut r = match event {
145            ct_event!(mouse down Left for column, row) => {
146                if self.header_area.contains((*column, *row).into()) {
147                    if let Some(col) = self.column_at_clicked((*column, *row)) {
148                        TableOutcome::Header(col)
149                    } else {
150                        TableOutcome::Continue
151                    }
152                } else if self.footer_area.contains((*column, *row).into()) {
153                    if let Some(col) = self.column_at_clicked((*column, *row)) {
154                        TableOutcome::Footer(col)
155                    } else {
156                        TableOutcome::Continue
157                    }
158                } else {
159                    TableOutcome::Continue
160                }
161            }
162            _ => TableOutcome::Continue,
163        };
164
165        r = r.or_else(|| {
166            let mut sas = ScrollAreaState::new()
167                .area(self.inner)
168                .h_scroll(&mut self.hscroll)
169                .v_scroll(&mut self.vscroll);
170
171            match sas.handle(event, MouseOnly) {
172                ScrollOutcome::Up(v) => {
173                    if self.scroll_up(v) {
174                        TableOutcome::Changed
175                    } else {
176                        TableOutcome::Unchanged
177                    }
178                }
179                ScrollOutcome::Down(v) => {
180                    if self.scroll_down(v) {
181                        TableOutcome::Changed
182                    } else {
183                        TableOutcome::Unchanged
184                    }
185                }
186                ScrollOutcome::VPos(v) => {
187                    if self.set_row_offset(v) {
188                        TableOutcome::Changed
189                    } else {
190                        TableOutcome::Unchanged
191                    }
192                }
193                ScrollOutcome::Left(v) => {
194                    if self.scroll_left(v) {
195                        TableOutcome::Changed
196                    } else {
197                        TableOutcome::Unchanged
198                    }
199                }
200                ScrollOutcome::Right(v) => {
201                    if self.scroll_right(v) {
202                        TableOutcome::Changed
203                    } else {
204                        TableOutcome::Unchanged
205                    }
206                }
207                ScrollOutcome::HPos(v) => {
208                    if self.set_x_offset(v) {
209                        TableOutcome::Changed
210                    } else {
211                        TableOutcome::Unchanged
212                    }
213                }
214                ScrollOutcome::Continue => TableOutcome::Continue,
215                ScrollOutcome::Unchanged => TableOutcome::Unchanged,
216                ScrollOutcome::Changed => TableOutcome::Changed,
217            }
218        });
219
220        r
221    }
222}
223
224/// Handle all events.
225/// Table events are only processed if focus is true.
226/// Mouse events are processed if they are in range.
227pub fn handle_events(
228    state: &mut TableState<NoSelection>,
229    focus: bool,
230    event: &Event,
231) -> TableOutcome {
232    state.focus.set(focus);
233    state.handle(event, Regular)
234}
235
236/// Handle only mouse-events.
237pub fn handle_mouse_events(state: &mut TableState<NoSelection>, event: &Event) -> TableOutcome {
238    state.handle(event, MouseOnly)
239}