Add support for Mouse Events
This commit is contained in:
parent
87bc923f0a
commit
8d7d074933
4 changed files with 404 additions and 130 deletions
|
|
@ -32,6 +32,7 @@ use tokio::sync::mpsc;
|
||||||
|
|
||||||
use config::{AppTheme, Config, CONFIG_VERSION};
|
use config::{AppTheme, Config, CONFIG_VERSION};
|
||||||
mod config;
|
mod config;
|
||||||
|
mod mouse_reporter;
|
||||||
|
|
||||||
use icon_cache::IconCache;
|
use icon_cache::IconCache;
|
||||||
mod icon_cache;
|
mod icon_cache;
|
||||||
|
|
|
||||||
197
src/mouse_reporter.rs
Normal file
197
src/mouse_reporter.rs
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
use cosmic::{
|
||||||
|
iced::mouse::{Event as MouseEvent, ScrollDelta},
|
||||||
|
iced::{keyboard::Modifiers, mouse::Button, Event},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::terminal::Terminal;
|
||||||
|
|
||||||
|
const SCROLL_SPEED: u32 = 3;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MouseReporter {
|
||||||
|
last_movment_x: Option<u32>,
|
||||||
|
last_movment_y: Option<u32>,
|
||||||
|
button: Option<Button>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseReporter {
|
||||||
|
fn button_number(&self, button: Button) -> Option<u8> {
|
||||||
|
match button {
|
||||||
|
Button::Left => Some(0),
|
||||||
|
Button::Middle => Some(1),
|
||||||
|
Button::Right => Some(2),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Implemented according to
|
||||||
|
//https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
|
||||||
|
pub fn normal_mouse_code(
|
||||||
|
&mut self,
|
||||||
|
event: Event,
|
||||||
|
modifiers: &Modifiers,
|
||||||
|
is_utf8: bool,
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
) -> Option<Vec<u8>> {
|
||||||
|
//Buttons are handle slightly different between normal and sgr
|
||||||
|
//for normal/utf8 the button release is always reported as button 3
|
||||||
|
let Some(mut button) = (match event {
|
||||||
|
Event::Mouse(MouseEvent::ButtonPressed(b)) => {
|
||||||
|
self.button = Some(b);
|
||||||
|
self.button_number(b)
|
||||||
|
}
|
||||||
|
Event::Mouse(MouseEvent::ButtonReleased(_b)) => {
|
||||||
|
self.button = None;
|
||||||
|
Some(3)
|
||||||
|
}
|
||||||
|
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
||||||
|
//Button pressed is reported as button 32 + 0,1,2 and event code M
|
||||||
|
//And only reported if a button is previously pressed
|
||||||
|
if (self.last_movment_x, self.last_movment_y) == (Some(x), Some(y)) {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
self.last_movment_x = Some(x);
|
||||||
|
self.last_movment_y = Some(y);
|
||||||
|
}
|
||||||
|
//It seems that we should add 32 to signal movement even for normal mode
|
||||||
|
//On button-motion events, xterm adds 32 to the event code (the third
|
||||||
|
//character, Cb).
|
||||||
|
//For example, motion into cell x,y with button 1 down is reported as
|
||||||
|
//CSI M @ CxCy ( @ = 32 + 0 (button 1) + 32 (motion indicator) ).
|
||||||
|
self.button
|
||||||
|
.and_then(|button| self.button_number(button))
|
||||||
|
.map(|b| b + 32)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if modifiers.shift() {
|
||||||
|
button += 4;
|
||||||
|
}
|
||||||
|
if modifiers.alt() {
|
||||||
|
button += 8;
|
||||||
|
}
|
||||||
|
if modifiers.control() {
|
||||||
|
button += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Normal mode have a max of 223 (255 - 32), while utf8 extend this to 2015
|
||||||
|
let max_point: usize = if is_utf8 { 2015 } else { 223 };
|
||||||
|
if x as usize >= max_point || y as usize >= max_point {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let utf8_encode_and_append = |mut pos: u32, dest: &mut Vec<u8>| {
|
||||||
|
pos += 1 + 32;
|
||||||
|
let mut utf8 = [0; 2]; //This is large enough since we have a max of 2015
|
||||||
|
dest.extend_from_slice(
|
||||||
|
(char::from_u32(pos).unwrap()) //This unwrap and encode_utf8 is safe due to our
|
||||||
|
//specific range, pos will max be 2047
|
||||||
|
.encode_utf8(&mut utf8)
|
||||||
|
.as_bytes(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
//SPEC: Likewise, Cb will be UTF-8 encoded, to reduce confusion with wheel mouse events.
|
||||||
|
//Always, or only when the the cooardinates is used? No other terminal seems to do this a
|
||||||
|
//all? Doing what they are doing for now.
|
||||||
|
let mut buf: Vec<u8> = vec![b'\x1b', b'[', b'M', 32 + button];
|
||||||
|
//Should we remove 32+button from previous line, and use this instead? Or only on >= 95
|
||||||
|
//utf8_encode_and_append(32 + button, &mut buf);
|
||||||
|
|
||||||
|
//For utf8 spec say: For positions less than 95, the resulting output is identical under both modes.
|
||||||
|
//But also: Under normal mouse mode, positions outside (160,94) result in byte pairs which can be interpreted as a single UTF-8
|
||||||
|
if is_utf8 && x >= 95 {
|
||||||
|
utf8_encode_and_append(x, &mut buf);
|
||||||
|
} else {
|
||||||
|
//SPEC: For positions less than 95, the resulting output is identical under both modes.
|
||||||
|
buf.push(32 + 1 + x as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_utf8 && y >= 95 {
|
||||||
|
utf8_encode_and_append(y, &mut buf);
|
||||||
|
} else {
|
||||||
|
//SPEC For positions less than 95, the resulting output is identical under both modes.
|
||||||
|
buf.push(32 + 1 + y as u8);
|
||||||
|
}
|
||||||
|
Some(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sgr_mouse_code(
|
||||||
|
&mut self,
|
||||||
|
event: Event,
|
||||||
|
modifiers: &Modifiers,
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
) -> Option<Vec<u8>> {
|
||||||
|
let Some((button_no, event_code)) = (match event {
|
||||||
|
Event::Mouse(MouseEvent::ButtonPressed(button)) => {
|
||||||
|
//Button pressed is reported as button 0,1,2 and event code M
|
||||||
|
self.button = Some(button);
|
||||||
|
Some((self.button_number(button), "M"))
|
||||||
|
}
|
||||||
|
Event::Mouse(MouseEvent::ButtonReleased(button)) => {
|
||||||
|
//Button pressed is reported as button 0,1,2 and event code m
|
||||||
|
self.button = None;
|
||||||
|
Some((self.button_number(button), "m"))
|
||||||
|
}
|
||||||
|
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
||||||
|
//Button pressed is reported as button 32 + 0,1,2 and event code M
|
||||||
|
//And only reported if a button is previously pressed
|
||||||
|
if (self.last_movment_x, self.last_movment_y) == (Some(x), Some(y)) {
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
|
self.last_movment_x = Some(x);
|
||||||
|
self.last_movment_y = Some(y);
|
||||||
|
}
|
||||||
|
self.button
|
||||||
|
.map(|button| (self.button_number(button).map(|b| b + 32), "M"))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut button_no) = button_no {
|
||||||
|
if modifiers.shift() {
|
||||||
|
button_no += 4;
|
||||||
|
}
|
||||||
|
if modifiers.alt() {
|
||||||
|
button_no += 8;
|
||||||
|
}
|
||||||
|
if modifiers.control() {
|
||||||
|
button_no += 16;
|
||||||
|
}
|
||||||
|
let term_code = format!("\x1b[<{};{};{}{}", button_no, x + 1, y + 1, event_code);
|
||||||
|
Some(term_code.as_bytes().to_vec())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Emulate mouse wheel scroll with up/down arrows. Using mouse spec uses
|
||||||
|
//scroll-back and scroll-forw actions, which moves whole windows like page up/page down.
|
||||||
|
pub fn report_mouse_wheel_scroll(
|
||||||
|
&self,
|
||||||
|
terminal: &Terminal,
|
||||||
|
term_cell_width: f32,
|
||||||
|
term_cell_height: f32,
|
||||||
|
delta: ScrollDelta,
|
||||||
|
) {
|
||||||
|
let (_delta_x, delta_y) = match delta {
|
||||||
|
ScrollDelta::Lines { x, y } => (x, y),
|
||||||
|
ScrollDelta::Pixels { x, y } => (x / term_cell_width, y / term_cell_height),
|
||||||
|
};
|
||||||
|
//Send delta_y * SCROLL_SPEED number of Up/Down arrows
|
||||||
|
for _ in 0..(delta_y.abs() as u32 * SCROLL_SPEED) {
|
||||||
|
if delta_y > 0.0 {
|
||||||
|
terminal.input_no_scroll(b"\x1B[1;3A".as_slice())
|
||||||
|
} else if delta_y < 0.0 {
|
||||||
|
terminal.input_no_scroll(b"\x1B[1;3B".as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ use alacritty_terminal::{
|
||||||
};
|
};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::advanced::graphics::text::font_system,
|
iced::advanced::graphics::text::font_system,
|
||||||
|
iced::mouse::ScrollDelta,
|
||||||
widget::{pane_grid, segmented_button},
|
widget::{pane_grid, segmented_button},
|
||||||
};
|
};
|
||||||
use cosmic_text::{
|
use cosmic_text::{
|
||||||
|
|
@ -34,7 +35,7 @@ use tokio::sync::mpsc;
|
||||||
|
|
||||||
pub use alacritty_terminal::grid::Scroll as TerminalScroll;
|
pub use alacritty_terminal::grid::Scroll as TerminalScroll;
|
||||||
|
|
||||||
use crate::config::Config as AppConfig;
|
use crate::{config::Config as AppConfig, mouse_reporter::MouseReporter};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
|
|
@ -189,6 +190,7 @@ pub struct Terminal {
|
||||||
search_regex_opt: Option<RegexSearch>,
|
search_regex_opt: Option<RegexSearch>,
|
||||||
search_value: String,
|
search_value: String,
|
||||||
pub metadata_set: IndexSet<Metadata>,
|
pub metadata_set: IndexSet<Metadata>,
|
||||||
|
mouse_reporter: MouseReporter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Terminal {
|
impl Terminal {
|
||||||
|
|
@ -275,6 +277,7 @@ impl Terminal {
|
||||||
search_regex_opt: None,
|
search_regex_opt: None,
|
||||||
search_value: String::new(),
|
search_value: String::new(),
|
||||||
metadata_set,
|
metadata_set,
|
||||||
|
mouse_reporter: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -776,6 +779,40 @@ impl Terminal {
|
||||||
let term = self.term.lock();
|
let term = self.term.lock();
|
||||||
viewport_to_point(term.grid().display_offset(), point)
|
viewport_to_point(term.grid().display_offset(), point)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn report_mouse(
|
||||||
|
&mut self,
|
||||||
|
event: cosmic::iced::Event,
|
||||||
|
modifiers: &cosmic::iced::keyboard::Modifiers,
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
) {
|
||||||
|
let term_lock = self.term.lock();
|
||||||
|
let mode = term_lock.mode();
|
||||||
|
if mode.contains(TermMode::SGR_MOUSE) {
|
||||||
|
if let Some(code) = self.mouse_reporter.sgr_mouse_code(event, modifiers, x, y) {
|
||||||
|
self.input_no_scroll(code)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(code) = self.mouse_reporter.normal_mouse_code(
|
||||||
|
event,
|
||||||
|
modifiers,
|
||||||
|
mode.contains(TermMode::UTF8_MOUSE),
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
) {
|
||||||
|
self.input_no_scroll(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn scroll_mouse(&mut self, delta: ScrollDelta) {
|
||||||
|
self.mouse_reporter.report_mouse_wheel_scroll(
|
||||||
|
self,
|
||||||
|
self.size().cell_width,
|
||||||
|
self.size().cell_height,
|
||||||
|
delta,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Terminal {
|
impl Drop for Terminal {
|
||||||
|
|
|
||||||
|
|
@ -594,6 +594,7 @@ where
|
||||||
let buffer_size = terminal.with_buffer(|buffer| buffer.size());
|
let buffer_size = terminal.with_buffer(|buffer| buffer.size());
|
||||||
|
|
||||||
let is_app_cursor = terminal.term.lock().mode().contains(TermMode::APP_CURSOR);
|
let is_app_cursor = terminal.term.lock().mode().contains(TermMode::APP_CURSOR);
|
||||||
|
let is_mouse_mode = terminal.term.lock().mode().intersects(TermMode::MOUSE_MODE);
|
||||||
|
|
||||||
let mut status = Status::Ignored;
|
let mut status = Status::Ignored;
|
||||||
match event {
|
match event {
|
||||||
|
|
@ -1009,98 +1010,128 @@ where
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::ButtonPressed(button)) => {
|
Event::Mouse(MouseEvent::ButtonPressed(button)) => {
|
||||||
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
||||||
state.is_focused = true;
|
let x = p.x - self.padding.left;
|
||||||
|
let y = p.y - self.padding.top;
|
||||||
|
//TODO: better calculation of position
|
||||||
|
let col = x / terminal.size().cell_width;
|
||||||
|
let row = y / terminal.size().cell_height;
|
||||||
|
|
||||||
// Handle left click drag
|
if is_mouse_mode {
|
||||||
if let Button::Left = button {
|
terminal.report_mouse(event, &state.modifiers, col as u32, row as u32);
|
||||||
let x = p.x - self.padding.left;
|
} else {
|
||||||
let y = p.y - self.padding.top;
|
state.is_focused = true;
|
||||||
if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 {
|
|
||||||
let click_kind =
|
// Handle left click drag
|
||||||
if let Some((click_kind, click_time)) = state.click.take() {
|
if let Button::Left = button {
|
||||||
if click_time.elapsed() < self.click_timing {
|
let x = p.x - self.padding.left;
|
||||||
match click_kind {
|
let y = p.y - self.padding.top;
|
||||||
ClickKind::Single => ClickKind::Double,
|
if x >= 0.0 && x < buffer_size.0 && y >= 0.0 && y < buffer_size.1 {
|
||||||
ClickKind::Double => ClickKind::Triple,
|
let click_kind =
|
||||||
ClickKind::Triple => ClickKind::Single,
|
if let Some((click_kind, click_time)) = state.click.take() {
|
||||||
|
if click_time.elapsed() < self.click_timing {
|
||||||
|
match click_kind {
|
||||||
|
ClickKind::Single => ClickKind::Double,
|
||||||
|
ClickKind::Double => ClickKind::Triple,
|
||||||
|
ClickKind::Triple => ClickKind::Single,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ClickKind::Single
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ClickKind::Single
|
ClickKind::Single
|
||||||
}
|
};
|
||||||
|
let location = terminal.viewport_to_point(TermPoint::new(
|
||||||
|
row as usize,
|
||||||
|
TermColumn(col as usize),
|
||||||
|
));
|
||||||
|
let side = if col.fract() < 0.5 {
|
||||||
|
TermSide::Left
|
||||||
} else {
|
} else {
|
||||||
ClickKind::Single
|
TermSide::Right
|
||||||
};
|
};
|
||||||
//TODO: better calculation of position
|
let selection = match click_kind {
|
||||||
let col = x / terminal.size().cell_width;
|
ClickKind::Single => {
|
||||||
let row = y / terminal.size().cell_height;
|
Selection::new(SelectionType::Simple, location, side)
|
||||||
let location = terminal.viewport_to_point(TermPoint::new(
|
}
|
||||||
row as usize,
|
ClickKind::Double => {
|
||||||
TermColumn(col as usize),
|
Selection::new(SelectionType::Semantic, location, side)
|
||||||
));
|
}
|
||||||
let side = if col.fract() < 0.5 {
|
ClickKind::Triple => {
|
||||||
TermSide::Left
|
Selection::new(SelectionType::Lines, location, side)
|
||||||
} else {
|
}
|
||||||
TermSide::Right
|
};
|
||||||
};
|
{
|
||||||
let selection = match click_kind {
|
let mut term = terminal.term.lock();
|
||||||
ClickKind::Single => {
|
term.selection = Some(selection);
|
||||||
Selection::new(SelectionType::Simple, location, side)
|
|
||||||
}
|
}
|
||||||
ClickKind::Double => {
|
terminal.needs_update = true;
|
||||||
Selection::new(SelectionType::Semantic, location, side)
|
state.click = Some((click_kind, Instant::now()));
|
||||||
}
|
state.dragging = Some(Dragging::Buffer);
|
||||||
ClickKind::Triple => {
|
} else if scrollbar_rect.contains(Point::new(x, y)) {
|
||||||
Selection::new(SelectionType::Lines, location, side)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
{
|
|
||||||
let mut term = terminal.term.lock();
|
|
||||||
term.selection = Some(selection);
|
|
||||||
}
|
|
||||||
terminal.needs_update = true;
|
|
||||||
state.click = Some((click_kind, Instant::now()));
|
|
||||||
state.dragging = Some(Dragging::Buffer);
|
|
||||||
} else if scrollbar_rect.contains(Point::new(x, y)) {
|
|
||||||
if let Some(start_scroll) = terminal.scrollbar() {
|
|
||||||
state.dragging = Some(Dragging::Scrollbar {
|
|
||||||
start_y: y,
|
|
||||||
start_scroll,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if x >= scrollbar_rect.x
|
|
||||||
&& x < (scrollbar_rect.x + scrollbar_rect.width)
|
|
||||||
{
|
|
||||||
if terminal.scrollbar().is_some() {
|
|
||||||
let scroll_ratio =
|
|
||||||
terminal.with_buffer(|buffer| y / buffer.size().1);
|
|
||||||
terminal.scroll_to(scroll_ratio);
|
|
||||||
if let Some(start_scroll) = terminal.scrollbar() {
|
if let Some(start_scroll) = terminal.scrollbar() {
|
||||||
state.dragging = Some(Dragging::Scrollbar {
|
state.dragging = Some(Dragging::Scrollbar {
|
||||||
start_y: y,
|
start_y: y,
|
||||||
start_scroll,
|
start_scroll,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else if x >= scrollbar_rect.x
|
||||||
|
&& x < (scrollbar_rect.x + scrollbar_rect.width)
|
||||||
|
{
|
||||||
|
if terminal.scrollbar().is_some() {
|
||||||
|
let scroll_ratio =
|
||||||
|
terminal.with_buffer(|buffer| y / buffer.size().1);
|
||||||
|
terminal.scroll_to(scroll_ratio);
|
||||||
|
if let Some(start_scroll) = terminal.scrollbar() {
|
||||||
|
state.dragging = Some(Dragging::Scrollbar {
|
||||||
|
start_y: y,
|
||||||
|
start_scroll,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Update context menu state
|
||||||
|
if let Some(on_context_menu) = &self.on_context_menu {
|
||||||
|
shell.publish((on_context_menu)(match self.context_menu {
|
||||||
|
Some(_) => None,
|
||||||
|
None => match button {
|
||||||
|
Button::Right => Some(p),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update context menu state
|
|
||||||
if let Some(on_context_menu) = &self.on_context_menu {
|
|
||||||
shell.publish((on_context_menu)(match self.context_menu {
|
|
||||||
Some(_) => None,
|
|
||||||
None => match button {
|
|
||||||
Button::Right => Some(p),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
status = Status::Captured;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::ButtonReleased(Button::Left)) => {
|
Event::Mouse(MouseEvent::ButtonReleased(Button::Left)) => {
|
||||||
state.dragging = None;
|
state.dragging = None;
|
||||||
status = Status::Captured;
|
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
||||||
|
let x = p.x - self.padding.left;
|
||||||
|
let y = p.y - self.padding.top;
|
||||||
|
//TODO: better calculation of position
|
||||||
|
let col = x / terminal.size().cell_width;
|
||||||
|
let row = y / terminal.size().cell_height;
|
||||||
|
if is_mouse_mode {
|
||||||
|
terminal.report_mouse(event, &state.modifiers, col as u32, row as u32);
|
||||||
|
} else {
|
||||||
|
status = Status::Captured;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = Status::Captured;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::Mouse(MouseEvent::ButtonReleased(_button)) => {
|
||||||
|
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
||||||
|
let x = p.x - self.padding.left;
|
||||||
|
let y = p.y - self.padding.top;
|
||||||
|
//TODO: better calculation of position
|
||||||
|
let col = x / terminal.size().cell_width;
|
||||||
|
let row = y / terminal.size().cell_height;
|
||||||
|
if is_mouse_mode {
|
||||||
|
terminal.report_mouse(event, &state.modifiers, col as u32, row as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
||||||
if let Some(on_mouse_enter) = &self.on_mouse_enter {
|
if let Some(on_mouse_enter) = &self.on_mouse_enter {
|
||||||
|
|
@ -1116,74 +1147,82 @@ where
|
||||||
self.mouse_inside_boundary = Some(mouse_is_inside);
|
self.mouse_inside_boundary = Some(mouse_is_inside);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(dragging) = &state.dragging {
|
if let Some(p) = cursor_position.position() {
|
||||||
if let Some(p) = cursor_position.position() {
|
let x = (p.x - layout.bounds().x) - self.padding.left;
|
||||||
let x = (p.x - layout.bounds().x) - self.padding.left;
|
let y = (p.y - layout.bounds().y) - self.padding.top;
|
||||||
let y = (p.y - layout.bounds().y) - self.padding.top;
|
//TODO: better calculation of position
|
||||||
match dragging {
|
let col = x / terminal.size().cell_width;
|
||||||
Dragging::Buffer => {
|
let row = y / terminal.size().cell_height;
|
||||||
//TODO: better calculation of position
|
if is_mouse_mode {
|
||||||
let col = x / terminal.size().cell_width;
|
terminal.report_mouse(event, &state.modifiers, col as u32, row as u32);
|
||||||
let row = y / terminal.size().cell_height;
|
} else {
|
||||||
let location = terminal.viewport_to_point(TermPoint::new(
|
if let Some(dragging) = &state.dragging {
|
||||||
row as usize,
|
match dragging {
|
||||||
TermColumn(col as usize),
|
Dragging::Buffer => {
|
||||||
));
|
let location = terminal.viewport_to_point(TermPoint::new(
|
||||||
let side = if col.fract() < 0.5 {
|
row as usize,
|
||||||
TermSide::Left
|
TermColumn(col as usize),
|
||||||
} else {
|
));
|
||||||
TermSide::Right
|
let side = if col.fract() < 0.5 {
|
||||||
};
|
TermSide::Left
|
||||||
{
|
} else {
|
||||||
let mut term = terminal.term.lock();
|
TermSide::Right
|
||||||
if let Some(selection) = &mut term.selection {
|
};
|
||||||
selection.update(location, side);
|
{
|
||||||
|
let mut term = terminal.term.lock();
|
||||||
|
if let Some(selection) = &mut term.selection {
|
||||||
|
selection.update(location, side);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
terminal.needs_update = true;
|
||||||
|
}
|
||||||
|
Dragging::Scrollbar {
|
||||||
|
start_y,
|
||||||
|
start_scroll,
|
||||||
|
} => {
|
||||||
|
let scroll_offset = terminal
|
||||||
|
.with_buffer(|buffer| ((y - start_y) / buffer.size().1));
|
||||||
|
terminal.scroll_to(start_scroll.0 + scroll_offset);
|
||||||
}
|
}
|
||||||
terminal.needs_update = true;
|
|
||||||
}
|
|
||||||
Dragging::Scrollbar {
|
|
||||||
start_y,
|
|
||||||
start_scroll,
|
|
||||||
} => {
|
|
||||||
let scroll_offset = terminal
|
|
||||||
.with_buffer(|buffer| ((y - start_y) / buffer.size().1));
|
|
||||||
terminal.scroll_to(start_scroll.0 + scroll_offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
status = Status::Captured;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::WheelScrolled { delta }) => {
|
Event::Mouse(MouseEvent::WheelScrolled { delta }) => {
|
||||||
if let Some(_p) = cursor_position.position_in(layout.bounds()) {
|
if let Some(_p) = cursor_position.position_in(layout.bounds()) {
|
||||||
match delta {
|
if is_mouse_mode {
|
||||||
ScrollDelta::Lines { x: _, y } => {
|
terminal.scroll_mouse(delta);
|
||||||
//TODO: this adjustment is just a guess!
|
} else {
|
||||||
state.scroll_pixels = 0.0;
|
match delta {
|
||||||
let lines = (-y * 6.0) as i32;
|
ScrollDelta::Lines { x: _, y } => {
|
||||||
if lines != 0 {
|
//TODO: this adjustment is just a guess!
|
||||||
terminal.scroll(TerminalScroll::Delta(-lines));
|
state.scroll_pixels = 0.0;
|
||||||
|
let lines = (-y * 6.0) as i32;
|
||||||
|
if lines != 0 {
|
||||||
|
terminal.scroll(TerminalScroll::Delta(-lines));
|
||||||
|
}
|
||||||
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
status = Status::Captured;
|
ScrollDelta::Pixels { x: _, y } => {
|
||||||
}
|
//TODO: this adjustment is just a guess!
|
||||||
ScrollDelta::Pixels { x: _, y } => {
|
state.scroll_pixels -= y * 6.0;
|
||||||
//TODO: this adjustment is just a guess!
|
let mut lines = 0;
|
||||||
state.scroll_pixels -= y * 6.0;
|
let metrics = terminal.with_buffer(|buffer| buffer.metrics());
|
||||||
let mut lines = 0;
|
while state.scroll_pixels <= -metrics.line_height {
|
||||||
let metrics = terminal.with_buffer(|buffer| buffer.metrics());
|
lines -= 1;
|
||||||
while state.scroll_pixels <= -metrics.line_height {
|
state.scroll_pixels += metrics.line_height;
|
||||||
lines -= 1;
|
}
|
||||||
state.scroll_pixels += metrics.line_height;
|
while state.scroll_pixels >= metrics.line_height {
|
||||||
|
lines += 1;
|
||||||
|
state.scroll_pixels -= metrics.line_height;
|
||||||
|
}
|
||||||
|
if lines != 0 {
|
||||||
|
terminal.scroll(TerminalScroll::Delta(-lines));
|
||||||
|
}
|
||||||
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
while state.scroll_pixels >= metrics.line_height {
|
|
||||||
lines += 1;
|
|
||||||
state.scroll_pixels -= metrics.line_height;
|
|
||||||
}
|
|
||||||
if lines != 0 {
|
|
||||||
terminal.scroll(TerminalScroll::Delta(-lines));
|
|
||||||
}
|
|
||||||
status = Status::Captured;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue