rat_ftable/
noselection.rs

1use crate::event::TableOutcome;
2use crate::{TableSelection, TableState};
3use rat_event::{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        let mut sas = ScrollAreaState::new()
141            .area(self.inner)
142            .h_scroll(&mut self.hscroll)
143            .v_scroll(&mut self.vscroll);
144
145        match sas.handle(event, MouseOnly) {
146            ScrollOutcome::Up(v) => {
147                if self.scroll_up(v) {
148                    TableOutcome::Changed
149                } else {
150                    TableOutcome::Unchanged
151                }
152            }
153            ScrollOutcome::Down(v) => {
154                if self.scroll_down(v) {
155                    TableOutcome::Changed
156                } else {
157                    TableOutcome::Unchanged
158                }
159            }
160            ScrollOutcome::VPos(v) => {
161                if self.set_row_offset(v) {
162                    TableOutcome::Changed
163                } else {
164                    TableOutcome::Unchanged
165                }
166            }
167            ScrollOutcome::Left(v) => {
168                if self.scroll_left(v) {
169                    TableOutcome::Changed
170                } else {
171                    TableOutcome::Unchanged
172                }
173            }
174            ScrollOutcome::Right(v) => {
175                if self.scroll_right(v) {
176                    TableOutcome::Changed
177                } else {
178                    TableOutcome::Unchanged
179                }
180            }
181            ScrollOutcome::HPos(v) => {
182                if self.set_x_offset(v) {
183                    TableOutcome::Changed
184                } else {
185                    TableOutcome::Unchanged
186                }
187            }
188            ScrollOutcome::Continue => TableOutcome::Continue,
189            ScrollOutcome::Unchanged => TableOutcome::Unchanged,
190            ScrollOutcome::Changed => TableOutcome::Changed,
191        }
192    }
193}
194
195/// Handle all events.
196/// Table events are only processed if focus is true.
197/// Mouse events are processed if they are in range.
198pub fn handle_events(
199    state: &mut TableState<NoSelection>,
200    focus: bool,
201    event: &Event,
202) -> TableOutcome {
203    state.focus.set(focus);
204    state.handle(event, Regular)
205}
206
207/// Handle only mouse-events.
208pub fn handle_mouse_events(state: &mut TableState<NoSelection>, event: &Event) -> TableOutcome {
209    state.handle(event, MouseOnly)
210}