Skip to main content

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