diff --git a/helix-term/src/ui/popup.rs b/helix-term/src/ui/popup.rs index b38b8b6e3..4f379b4a1 100644 --- a/helix-term/src/ui/popup.rs +++ b/helix-term/src/ui/popup.rs @@ -11,6 +11,7 @@ use tui::{ use helix_core::Position; use helix_view::{ graphics::{Margin, Rect}, + input::{MouseEvent, MouseEventKind}, Editor, }; @@ -23,6 +24,7 @@ pub struct Popup { margin: Margin, size: (u16, u16), child_size: (u16, u16), + area: Rect, position_bias: Open, scroll: usize, auto_close: bool, @@ -40,6 +42,7 @@ impl Popup { size: (0, 0), position_bias: Open::Below, child_size: (0, 0), + area: Rect::new(0, 0, 0, 0), scroll: 0, auto_close: false, ignore_escape_key: false, @@ -146,6 +149,14 @@ impl Popup { } } + pub fn scroll_half_page_down(&mut self) { + self.scroll(self.size.1 as usize / 2, true) + } + + pub fn scroll_half_page_up(&mut self) { + self.scroll(self.size.1 as usize / 2, false) + } + /// Toggles the Popup's scrollbar. /// Consider disabling the scrollbar in case the child /// already has its own. @@ -171,12 +182,44 @@ impl Popup { // clip to viewport viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1)) } + + fn handle_mouse_event( + &mut self, + &MouseEvent { + kind, + column: x, + row: y, + .. + }: &MouseEvent, + ) -> EventResult { + let mouse_is_within_popup = x >= self.area.left() + && x < self.area.right() + && y >= self.area.top() + && y < self.area.bottom(); + + if !mouse_is_within_popup { + return EventResult::Ignored(None); + } + + match kind { + MouseEventKind::ScrollDown if self.has_scrollbar => { + self.scroll_half_page_down(); + EventResult::Consumed(None) + } + MouseEventKind::ScrollUp if self.has_scrollbar => { + self.scroll_half_page_up(); + EventResult::Consumed(None) + } + _ => EventResult::Ignored(None), + } + } } impl Component for Popup { fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult { let key = match event { Event::Key(event) => *event, + Event::Mouse(event) => return self.handle_mouse_event(event), Event::Resize(_, _) => { // TODO: calculate inner area, call component's handle_event with that area return EventResult::Ignored(None); @@ -200,11 +243,11 @@ impl Component for Popup { EventResult::Consumed(Some(close_fn)) } ctrl!('d') => { - self.scroll(self.size.1 as usize / 2, true); + self.scroll_half_page_down(); EventResult::Consumed(None) } ctrl!('u') => { - self.scroll(self.size.1 as usize / 2, false); + self.scroll_half_page_up(); EventResult::Consumed(None) } _ => { @@ -249,6 +292,7 @@ impl Component for Popup { fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) { let area = self.area(viewport, cx.editor); + self.area = area; cx.scroll = Some(self.scroll); // clear area