Skip to content

Commit 4f7a861

Browse files
author
slundi
committed
feat(tui): mouse support
Ref: #261
1 parent d0fcc71 commit 4f7a861

2 files changed

Lines changed: 70 additions & 4 deletions

File tree

src/view/app.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::sync::Arc;
22

33
use ::crossterm::event::KeyCode;
4-
use crossterm::event::{KeyEvent, KeyModifiers};
4+
use crossterm::event::{KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
55
use ratatui::Frame;
66
use ratatui::buffer::Buffer;
7-
use ratatui::layout::{Constraint, Layout, Rect};
7+
use ratatui::layout::{Constraint, Layout, Position, Rect};
88
use ratatui::widgets::{Block, Borders, Tabs, Widget};
99
use ratatui_image::picker::Picker;
1010
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel};
@@ -62,6 +62,7 @@ where
6262
// terminal font size and the graphics it supports
6363
// if the terminal doesn't support any graphics protocol the picker is `None`
6464
picker: Option<Picker>,
65+
top_tabs_area: Rect,
6566
}
6667

6768
impl<T, S> Component for App<T, S>
@@ -79,6 +80,7 @@ where
7980

8081
let [top_tabs_area, page_area] = main_layout.areas(area);
8182

83+
self.top_tabs_area = top_tabs_area;
8284
self.render_top_tabs(top_tabs_area, frame.buffer_mut());
8385

8486
self.render_pages(page_area, frame);
@@ -92,6 +94,7 @@ where
9294
fn handle_events(&mut self, events: Events) {
9395
match events {
9496
Events::Key(key_event) => self.handle_key_events(key_event),
97+
Events::Mouse(mouse_event) => self.handle_mouse_events(mouse_event),
9598
Events::GoToMangaPage(manga) => self.go_to_manga_page(manga),
9699
Events::ReadChapter(chapter_response, manga_to_read) => {
97100
self.go_to_read_chapter(chapter_response, manga_to_read, self.manga_tracker.clone())
@@ -176,6 +179,7 @@ where
176179
state: AppState::Runnning,
177180
error_message: None,
178181
manga_provider: Arc::clone(&provider),
182+
top_tabs_area: Rect::default(),
179183
}
180184
}
181185

@@ -301,6 +305,30 @@ where
301305
}
302306
}
303307

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+
304332
fn go_search_page(&mut self) {
305333
if self.manga_page.is_some() {
306334
self.manga_page.as_mut().unwrap().clean_up();

src/view/pages/home.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::sync::Arc;
22
use std::time::Duration;
33

4-
use crossterm::event::{KeyCode, KeyEvent};
4+
use crossterm::event::{KeyCode, KeyEvent, MouseButton, MouseEvent, MouseEventKind};
55
use image::DynamicImage;
66
use ratatui::Frame;
77
use ratatui::buffer::Buffer;
8-
use ratatui::layout::{Constraint, Layout, Margin, Rect};
8+
use ratatui::layout::{Constraint, Layout, Margin, Position, Rect};
99
use ratatui::style::Stylize;
1010
use ratatui::text::{Line, Span, ToSpan};
1111
use ratatui::widgets::{Block, List, StatefulWidget, Widget};
@@ -67,6 +67,8 @@ where
6767
picker: Option<Picker>,
6868
tasks: JoinSet<()>,
6969
manga_provider: Arc<T>,
70+
popular_mangas_area: Rect,
71+
recently_added_area: Rect,
7072
}
7173

7274
impl<T> Component for Home<T>
@@ -81,6 +83,9 @@ where
8183

8284
let [carrousel_popular_mangas_area, latest_updates_area] = layout.areas(area);
8385

86+
self.popular_mangas_area = carrousel_popular_mangas_area;
87+
self.recently_added_area = latest_updates_area;
88+
8489
self.render_popular_mangas_carrousel(carrousel_popular_mangas_area, buf);
8590

8691
self.render_recently_added_mangas_area(latest_updates_area, buf);
@@ -115,6 +120,7 @@ where
115120
fn handle_events(&mut self, events: Events) {
116121
match events {
117122
Events::Key(key_event) => self.handle_key_events(key_event),
123+
Events::Mouse(mouse_event) => self.handle_mouse_events(mouse_event),
118124
Events::Tick => self.tick(),
119125
_ => {},
120126
}
@@ -143,6 +149,8 @@ where
143149
recently_added_manga_state: ImageState::default(),
144150
tasks: JoinSet::new(),
145151
manga_provider,
152+
popular_mangas_area: Rect::default(),
153+
recently_added_area: Rect::default(),
146154
}
147155
}
148156

@@ -429,6 +437,36 @@ where
429437
)
430438
}
431439

440+
fn handle_mouse_events(&mut self, mouse_event: MouseEvent) {
441+
let pos = Position::new(mouse_event.column, mouse_event.row);
442+
let in_popular = self.popular_mangas_area.contains(pos);
443+
444+
match mouse_event.kind {
445+
MouseEventKind::ScrollUp => {
446+
if in_popular {
447+
self.local_action_tx.send(HomeActions::SelectPreviousPopularManga).ok();
448+
} else {
449+
self.local_action_tx.send(HomeActions::SelectPreviousRecentlyAddedManga).ok();
450+
}
451+
},
452+
MouseEventKind::ScrollDown => {
453+
if in_popular {
454+
self.local_action_tx.send(HomeActions::SelectNextPopularManga).ok();
455+
} else {
456+
self.local_action_tx.send(HomeActions::SelectNextRecentlyAddedManga).ok();
457+
}
458+
},
459+
MouseEventKind::Down(MouseButton::Left) => {
460+
if in_popular {
461+
self.local_action_tx.send(HomeActions::GoToPopularMangaPage).ok();
462+
} else if self.recently_added_area.contains(pos) {
463+
self.local_action_tx.send(HomeActions::GoToRecentlyAddedMangaPage).ok();
464+
}
465+
},
466+
_ => {},
467+
}
468+
}
469+
432470
pub fn handle_key_events(&mut self, key_event: KeyEvent) {
433471
match key_event.code {
434472
KeyCode::Char('w') => {

0 commit comments

Comments
 (0)