mirror of https://github.com/helix-editor/helix
Support scrolling popup contents using mouse (#10053)
* Extract popup scrolling code into named functions * Scroll popup contents on mouse scroll event * Ignore mouse events outside the popup * Remove unneeded return statementpull/10064/head
parent
0da5865695
commit
957d030be9
|
@ -11,6 +11,7 @@ use tui::{
|
||||||
use helix_core::Position;
|
use helix_core::Position;
|
||||||
use helix_view::{
|
use helix_view::{
|
||||||
graphics::{Margin, Rect},
|
graphics::{Margin, Rect},
|
||||||
|
input::{MouseEvent, MouseEventKind},
|
||||||
Editor,
|
Editor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ pub struct Popup<T: Component> {
|
||||||
margin: Margin,
|
margin: Margin,
|
||||||
size: (u16, u16),
|
size: (u16, u16),
|
||||||
child_size: (u16, u16),
|
child_size: (u16, u16),
|
||||||
|
area: Rect,
|
||||||
position_bias: Open,
|
position_bias: Open,
|
||||||
scroll: usize,
|
scroll: usize,
|
||||||
auto_close: bool,
|
auto_close: bool,
|
||||||
|
@ -40,6 +42,7 @@ impl<T: Component> Popup<T> {
|
||||||
size: (0, 0),
|
size: (0, 0),
|
||||||
position_bias: Open::Below,
|
position_bias: Open::Below,
|
||||||
child_size: (0, 0),
|
child_size: (0, 0),
|
||||||
|
area: Rect::new(0, 0, 0, 0),
|
||||||
scroll: 0,
|
scroll: 0,
|
||||||
auto_close: false,
|
auto_close: false,
|
||||||
ignore_escape_key: false,
|
ignore_escape_key: false,
|
||||||
|
@ -146,6 +149,14 @@ impl<T: Component> Popup<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
/// Toggles the Popup's scrollbar.
|
||||||
/// Consider disabling the scrollbar in case the child
|
/// Consider disabling the scrollbar in case the child
|
||||||
/// already has its own.
|
/// already has its own.
|
||||||
|
@ -171,12 +182,44 @@ impl<T: Component> Popup<T> {
|
||||||
// clip to viewport
|
// clip to viewport
|
||||||
viewport.intersection(Rect::new(rel_x, rel_y, self.size.0, self.size.1))
|
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<T: Component> Component for Popup<T> {
|
impl<T: Component> Component for Popup<T> {
|
||||||
fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
|
fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
|
||||||
let key = match event {
|
let key = match event {
|
||||||
Event::Key(event) => *event,
|
Event::Key(event) => *event,
|
||||||
|
Event::Mouse(event) => return self.handle_mouse_event(event),
|
||||||
Event::Resize(_, _) => {
|
Event::Resize(_, _) => {
|
||||||
// TODO: calculate inner area, call component's handle_event with that area
|
// TODO: calculate inner area, call component's handle_event with that area
|
||||||
return EventResult::Ignored(None);
|
return EventResult::Ignored(None);
|
||||||
|
@ -200,11 +243,11 @@ impl<T: Component> Component for Popup<T> {
|
||||||
EventResult::Consumed(Some(close_fn))
|
EventResult::Consumed(Some(close_fn))
|
||||||
}
|
}
|
||||||
ctrl!('d') => {
|
ctrl!('d') => {
|
||||||
self.scroll(self.size.1 as usize / 2, true);
|
self.scroll_half_page_down();
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
}
|
}
|
||||||
ctrl!('u') => {
|
ctrl!('u') => {
|
||||||
self.scroll(self.size.1 as usize / 2, false);
|
self.scroll_half_page_up();
|
||||||
EventResult::Consumed(None)
|
EventResult::Consumed(None)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -249,6 +292,7 @@ impl<T: Component> Component for Popup<T> {
|
||||||
|
|
||||||
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
|
fn render(&mut self, viewport: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||||
let area = self.area(viewport, cx.editor);
|
let area = self.area(viewport, cx.editor);
|
||||||
|
self.area = area;
|
||||||
cx.scroll = Some(self.scroll);
|
cx.scroll = Some(self.scroll);
|
||||||
|
|
||||||
// clear area
|
// clear area
|
||||||
|
|
Loading…
Reference in New Issue