|
1 | 1 | use std::sync::Arc; |
2 | 2 |
|
3 | 3 | use ::crossterm::event::KeyCode; |
4 | | -use crossterm::event::{KeyEvent, KeyModifiers}; |
| 4 | +use crossterm::event::{KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind}; |
5 | 5 | use ratatui::Frame; |
6 | 6 | use ratatui::buffer::Buffer; |
7 | | -use ratatui::layout::{Constraint, Layout, Rect}; |
| 7 | +use ratatui::layout::{Constraint, Layout, Position, Rect}; |
8 | 8 | use ratatui::widgets::{Block, Borders, Tabs, Widget}; |
9 | 9 | use ratatui_image::picker::Picker; |
10 | 10 | use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel}; |
|
62 | 62 | // terminal font size and the graphics it supports |
63 | 63 | // if the terminal doesn't support any graphics protocol the picker is `None` |
64 | 64 | picker: Option<Picker>, |
| 65 | + top_tabs_area: Rect, |
65 | 66 | } |
66 | 67 |
|
67 | 68 | impl<T, S> Component for App<T, S> |
|
79 | 80 |
|
80 | 81 | let [top_tabs_area, page_area] = main_layout.areas(area); |
81 | 82 |
|
| 83 | + self.top_tabs_area = top_tabs_area; |
82 | 84 | self.render_top_tabs(top_tabs_area, frame.buffer_mut()); |
83 | 85 |
|
84 | 86 | self.render_pages(page_area, frame); |
|
92 | 94 | fn handle_events(&mut self, events: Events) { |
93 | 95 | match events { |
94 | 96 | Events::Key(key_event) => self.handle_key_events(key_event), |
| 97 | + Events::Mouse(mouse_event) => self.handle_mouse_events(mouse_event), |
95 | 98 | Events::GoToMangaPage(manga) => self.go_to_manga_page(manga), |
96 | 99 | Events::ReadChapter(chapter_response, manga_to_read) => { |
97 | 100 | self.go_to_read_chapter(chapter_response, manga_to_read, self.manga_tracker.clone()) |
@@ -176,6 +179,7 @@ where |
176 | 179 | state: AppState::Runnning, |
177 | 180 | error_message: None, |
178 | 181 | manga_provider: Arc::clone(&provider), |
| 182 | + top_tabs_area: Rect::default(), |
179 | 183 | } |
180 | 184 | } |
181 | 185 |
|
@@ -301,6 +305,30 @@ where |
301 | 305 | } |
302 | 306 | } |
303 | 307 |
|
| 308 | + fn handle_mouse_events(&mut self, mouse_event: MouseEvent) { |
| 309 | + if self.current_tab == SelectedPage::ReaderTab { |
| 310 | + return; |
| 311 | + } |
| 312 | + if let MouseEventKind::Down(MouseButton::Left) = mouse_event.kind { |
| 313 | + let pos = Position::new(mouse_event.column, mouse_event.row); |
| 314 | + if !self.top_tabs_area.contains(pos) { |
| 315 | + return; |
| 316 | + } |
| 317 | + let num_tabs: u16 = if self.current_tab == SelectedPage::MangaTab { 4 } else { 3 }; |
| 318 | + let tab_width = self.top_tabs_area.width / num_tabs; |
| 319 | + if tab_width == 0 { |
| 320 | + return; |
| 321 | + } |
| 322 | + let tab_index = ((mouse_event.column.saturating_sub(self.top_tabs_area.x)) / tab_width).min(num_tabs - 1); |
| 323 | + match tab_index { |
| 324 | + 0 => self.global_event_tx.send(Events::GoToHome).ok(), |
| 325 | + 1 => self.global_event_tx.send(Events::GoSearchPage).ok(), |
| 326 | + 2 => self.global_event_tx.send(Events::GoFeedPage).ok(), |
| 327 | + _ => None, |
| 328 | + }; |
| 329 | + } |
| 330 | + } |
| 331 | + |
304 | 332 | fn go_search_page(&mut self) { |
305 | 333 | if self.manga_page.is_some() { |
306 | 334 | self.manga_page.as_mut().unwrap().clean_up(); |
|
0 commit comments