diff --git a/crates/terminal/src/connected_el.rs b/crates/terminal/src/connected_el.rs index 020c71f4219608bb2c6577f35333e190ab0ff2d1..e241cb5822f39579c840b9bf43df7b1d927db40e 100644 --- a/crates/terminal/src/connected_el.rs +++ b/crates/terminal/src/connected_el.rs @@ -1,26 +1,22 @@ use alacritty_terminal::{ ansi::{Color as AnsiColor, Color::Named, CursorShape as AlacCursorShape, NamedColor}, - grid::{Dimensions, Scroll}, - index::{Column as GridCol, Direction, Line as GridLine, Point, Side}, + grid::Dimensions, + index::Point, selection::SelectionRange, - term::{ - cell::{Cell, Flags}, - TermMode, - }, + term::cell::{Cell, Flags}, }; use editor::{Cursor, CursorShape, HighlightedRange, HighlightedRangeLine}; use gpui::{ color::Color, - elements::*, fonts::{Properties, Style::Italic, TextStyle, Underline, Weight}, geometry::{ rect::RectF, vector::{vec2f, Vector2F}, }, - json::json, + serde_json::json, text_layout::{Line, RunStyle}, - Event, EventContext, FontCache, KeyDownEvent, ModelContext, MouseButton, MouseButtonEvent, - MouseRegion, PaintContext, Quad, ScrollWheelEvent, TextLayoutCache, WeakModelHandle, + Element, Event, EventContext, FontCache, KeyDownEvent, ModelContext, MouseButton, + MouseButtonEvent, MouseRegion, PaintContext, Quad, TextLayoutCache, WeakModelHandle, WeakViewHandle, }; use itertools::Itertools; @@ -29,12 +25,11 @@ use settings::Settings; use theme::TerminalStyle; use util::ResultExt; +use std::fmt::Debug; use std::{ - cmp::min, mem, ops::{Deref, Range}, }; -use std::{fmt::Debug, ops::Sub}; use crate::{ connected_view::{ConnectedView, DeployContextMenu}, @@ -42,11 +37,6 @@ use crate::{ Terminal, TerminalSize, }; -///Scrolling is unbearably sluggish by default. Alacritty supports a configurable -///Scroll multiplier that is set to 3 by default. This will be removed when I -///Implement scroll bars. -pub const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.; - ///The information generated during layout that is nescessary for painting pub struct LayoutState { cells: Vec, @@ -56,7 +46,6 @@ pub struct LayoutState { background_color: Color, selection_color: Color, size: TerminalSize, - display_offset: usize, } #[derive(Debug)] @@ -420,22 +409,13 @@ impl TerminalEl { fn generic_button_handler( connection: WeakModelHandle, origin: Vector2F, - cur_size: TerminalSize, - display_offset: usize, - f: impl Fn(&mut Terminal, Point, Direction, MouseButtonEvent, &mut ModelContext), + f: impl Fn(&mut Terminal, Vector2F, MouseButtonEvent, &mut ModelContext), ) -> impl Fn(MouseButtonEvent, &mut EventContext) { move |event, cx| { cx.focus_parent_view(); if let Some(conn_handle) = connection.upgrade(cx.app) { conn_handle.update(cx.app, |terminal, cx| { - let (point, side) = TerminalEl::mouse_to_cell_data( - event.position, - origin, - cur_size, - display_offset, - ); - - f(terminal, point, side, event, cx); + f(terminal, origin, event, cx); cx.notify(); }) @@ -448,8 +428,6 @@ impl TerminalEl { origin: Vector2F, view_id: usize, visible_bounds: RectF, - cur_size: TerminalSize, - display_offset: usize, cx: &mut PaintContext, ) { let connection = self.terminal; @@ -459,34 +437,20 @@ impl TerminalEl { if cx.is_parent_view_focused() { if let Some(conn_handle) = connection.upgrade(cx.app) { conn_handle.update(cx.app, |terminal, cx| { - let (point, side) = TerminalEl::mouse_to_cell_data( - event.position, - origin, - cur_size, - display_offset, - ); - - terminal.mouse_move(point, side, &event); - + terminal.mouse_move(&event, origin); cx.notify(); }) } } }) .on_drag(MouseButton::Left, move |_prev, event, cx| { - if let Some(conn_handle) = connection.upgrade(cx.app) { - conn_handle.update(cx.app, |terminal, cx| { - let (point, side) = TerminalEl::mouse_to_cell_data( - event.position, - origin, - cur_size, - display_offset, - ); - - terminal.mouse_drag(point, side); - - cx.notify(); - }) + if cx.is_parent_view_focused() { + if let Some(conn_handle) = connection.upgrade(cx.app) { + conn_handle.update(cx.app, |terminal, cx| { + terminal.mouse_drag(event, origin); + cx.notify(); + }) + } } }) .on_down( @@ -494,10 +458,8 @@ impl TerminalEl { TerminalEl::generic_button_handler( connection, origin, - cur_size, - display_offset, - move |terminal, point, side, _e, _cx| { - terminal.mouse_down(point, side); + move |terminal, origin, e, _cx| { + terminal.mouse_down(&e, origin); }, ), ) @@ -506,10 +468,8 @@ impl TerminalEl { TerminalEl::generic_button_handler( connection, origin, - cur_size, - display_offset, - move |terminal, point, side, _e, _cx| { - terminal.mouse_down(point, side); + move |terminal, origin, e, _cx| { + terminal.mouse_down(&e, origin); }, ), ) @@ -518,65 +478,61 @@ impl TerminalEl { TerminalEl::generic_button_handler( connection, origin, - cur_size, - display_offset, - move |terminal, point, side, _e, _cx| { - terminal.mouse_down(point, side); + move |terminal, origin, e, _cx| { + terminal.mouse_down(&e, origin); }, ), ) - //TODO - .on_click( + .on_up( MouseButton::Left, TerminalEl::generic_button_handler( connection, origin, - cur_size, - display_offset, - move |terminal, point, side, e, _cx| { - terminal.click(point, side, e.click_count); + move |terminal, origin, e, _cx| { + terminal.mouse_up(&e, origin); }, ), ) - .on_click( + .on_up( + MouseButton::Right, + TerminalEl::generic_button_handler( + connection, + origin, + move |terminal, origin, e, _cx| { + terminal.mouse_up(&e, origin); + }, + ), + ) + .on_up( MouseButton::Middle, TerminalEl::generic_button_handler( connection, origin, - cur_size, - display_offset, - move |terminal, point, side, e, _cx| { - terminal.click(point, side, e.click_count); + move |terminal, origin, e, _cx| { + terminal.mouse_up(&e, origin); + }, + ), + ) + .on_click( + MouseButton::Left, + TerminalEl::generic_button_handler( + connection, + origin, + move |terminal, origin, e, _cx| { + terminal.left_click(&e, origin); }, ), ) .on_click( MouseButton::Right, move |e @ MouseButtonEvent { position, .. }, cx| { - //Attempt to check the mode - if let Some(conn_handle) = connection.upgrade(cx.app) { - let handled = conn_handle.update(cx.app, |terminal, _cx| { - //Finally, we can check the mode! - if terminal.last_mode.intersects(TermMode::MOUSE_MODE) { - let (point, side) = TerminalEl::mouse_to_cell_data( - position, - origin, - cur_size, - display_offset, - ); - - terminal.click(point, side, e.click_count); - true - } else { - false - } - }); - - //If I put this up by the true, then we're in the wrong 'cx' - if !handled { - cx.dispatch_action(DeployContextMenu { position }); - } + let mouse_mode = if let Some(conn_handle) = connection.upgrade(cx.app) { + conn_handle.update(cx.app, |terminal, _cx| terminal.mouse_mode(e.shift)) } else { + //If we can't get the model handle, probably can't deploy the context menu + true + }; + if !mouse_mode { cx.dispatch_action(DeployContextMenu { position }); } }, @@ -615,47 +571,6 @@ impl TerminalEl { underline: Default::default(), } } - - pub fn mouse_to_cell_data( - pos: Vector2F, - origin: Vector2F, - cur_size: TerminalSize, - display_offset: usize, - ) -> (Point, alacritty_terminal::index::Direction) { - let pos = pos.sub(origin); - let point = { - let col = pos.x() / cur_size.cell_width; //TODO: underflow... - let col = min(GridCol(col as usize), cur_size.last_column()); - - let line = pos.y() / cur_size.line_height; - let line = min(line as i32, cur_size.bottommost_line().0); - - Point::new(GridLine(line - display_offset as i32), col) - }; - - //Copied (with modifications) from alacritty/src/input.rs > Processor::cell_side() - let side = { - let x = pos.0.x() as usize; - let cell_x = - x.saturating_sub(cur_size.cell_width as usize) % cur_size.cell_width as usize; - let half_cell_width = (cur_size.cell_width / 2.0) as usize; - - let additional_padding = - (cur_size.width() - cur_size.cell_width * 2.) % cur_size.cell_width; - let end_of_grid = cur_size.width() - cur_size.cell_width - additional_padding; - //Width: Pixels or columns? - if cell_x > half_cell_width - // Edge case when mouse leaves the window. - || x as f32 >= end_of_grid - { - Side::Right - } else { - Side::Left - } - }; - - (point, side) - } } impl Element for TerminalEl { @@ -712,7 +627,7 @@ impl Element for TerminalEl { ( cells, - dbg!(content.selection), + content.selection, content.cursor, content.display_offset, cursor_text, @@ -794,7 +709,6 @@ impl Element for TerminalEl { size: dimensions, rects, highlights, - display_offset, }, ) } @@ -813,14 +727,7 @@ impl Element for TerminalEl { let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.); //Elements are ephemeral, only at paint time do we know what could be clicked by a mouse - self.attach_mouse_handlers( - origin, - self.view.id(), - visible_bounds, - layout.size, - layout.display_offset, - cx, - ); + self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, cx); cx.paint_layer(clip_bounds, |cx| { //Start with a background color @@ -884,28 +791,22 @@ impl Element for TerminalEl { fn dispatch_event( &mut self, event: &gpui::Event, - _bounds: gpui::geometry::rect::RectF, + bounds: gpui::geometry::rect::RectF, visible_bounds: gpui::geometry::rect::RectF, layout: &mut Self::LayoutState, _paint: &mut Self::PaintState, cx: &mut gpui::EventContext, ) -> bool { match event { - Event::ScrollWheel(ScrollWheelEvent { - delta, position, .. - }) => visible_bounds - .contains_point(*position) + Event::ScrollWheel(e) => visible_bounds + .contains_point(e.position) .then(|| { - let scroll_lines = - (delta.y() / layout.size.line_height) * ALACRITTY_SCROLL_MULTIPLIER; + let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.); if let Some(terminal) = self.terminal.upgrade(cx.app) { - terminal.update(cx.app, |term, _| { - term.scroll(Scroll::Delta(scroll_lines.round() as i32)) - }); + terminal.update(cx.app, |term, _| term.scroll(e, origin)); + cx.notify(); } - - cx.notify(); }) .is_some(), Event::KeyDown(KeyDownEvent { keystroke, .. }) => { @@ -913,7 +814,6 @@ impl Element for TerminalEl { return false; } - //TODO Talk to keith about how to catch events emitted from an element. if let Some(view) = self.view.upgrade(cx.app) { view.update(cx.app, |view, cx| { view.clear_bel(cx); @@ -969,36 +869,3 @@ impl Element for TerminalEl { Some(layout.cursor.as_ref()?.bounding_rect(origin)) } } - -mod test { - - #[test] - fn test_mouse_to_selection() { - let term_width = 100.; - let term_height = 200.; - let cell_width = 10.; - let line_height = 20.; - let mouse_pos_x = 100.; //Window relative - let mouse_pos_y = 100.; //Window relative - let origin_x = 10.; - let origin_y = 20.; - - let cur_size = crate::connected_el::TerminalSize::new( - line_height, - cell_width, - gpui::geometry::vector::vec2f(term_width, term_height), - ); - - let mouse_pos = gpui::geometry::vector::vec2f(mouse_pos_x, mouse_pos_y); - let origin = gpui::geometry::vector::vec2f(origin_x, origin_y); //Position of terminal window, 1 'cell' in - let (point, _) = - crate::connected_el::TerminalEl::mouse_to_cell_data(mouse_pos, origin, cur_size, 0); - assert_eq!( - point, - alacritty_terminal::index::Point::new( - alacritty_terminal::index::Line(((mouse_pos_y - origin_y) / line_height) as i32), - alacritty_terminal::index::Column(((mouse_pos_x - origin_x) / cell_width) as usize), - ) - ); - } -} diff --git a/crates/terminal/src/mappings/mouse.rs b/crates/terminal/src/mappings/mouse.rs index dec67b68f72cd7a9378eb09064cddd9c0490e48a..7c524ed2f934d2a499d895f06a8bc73699fb26c5 100644 --- a/crates/terminal/src/mappings/mouse.rs +++ b/crates/terminal/src/mappings/mouse.rs @@ -1,16 +1,23 @@ +use std::cmp::min; +use std::iter::repeat; + +use alacritty_terminal::grid::Dimensions; /// Most of the code, and specifically the constants, in this are copied from Alacritty, /// with modifications for our circumstances -use alacritty_terminal::{index::Point, term::TermMode}; -use gpui::{MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; +use alacritty_terminal::index::{Column as GridCol, Line as GridLine, Point, Side}; +use alacritty_terminal::term::TermMode; +use gpui::{geometry::vector::Vector2F, MouseButtonEvent, MouseMovedEvent, ScrollWheelEvent}; + +use crate::TerminalSize; -pub struct Modifiers { +struct Modifiers { ctrl: bool, shift: bool, alt: bool, } impl Modifiers { - pub fn from_moved(e: &MouseMovedEvent) -> Self { + fn from_moved(e: &MouseMovedEvent) -> Self { Modifiers { ctrl: e.ctrl, shift: e.shift, @@ -18,7 +25,7 @@ impl Modifiers { } } - pub fn from_button(e: &MouseButtonEvent) -> Self { + fn from_button(e: &MouseButtonEvent) -> Self { Modifiers { ctrl: e.ctrl, shift: e.shift, @@ -27,7 +34,7 @@ impl Modifiers { } //TODO: Determine if I should add modifiers into the ScrollWheelEvent type - pub fn from_scroll() -> Self { + fn from_scroll() -> Self { Modifiers { ctrl: false, shift: false, @@ -36,13 +43,13 @@ impl Modifiers { } } -pub enum MouseFormat { +enum MouseFormat { SGR, Normal(bool), } impl MouseFormat { - pub fn from_mode(mode: TermMode) -> Self { + fn from_mode(mode: TermMode) -> Self { if mode.contains(TermMode::SGR_MOUSE) { MouseFormat::SGR } else if mode.contains(TermMode::UTF8_MOUSE) { @@ -53,7 +60,7 @@ impl MouseFormat { } } -pub enum MouseButton { +enum MouseButton { LeftButton = 0, MiddleButton = 1, RightButton = 2, @@ -67,7 +74,7 @@ pub enum MouseButton { } impl MouseButton { - pub fn from_move(e: &MouseMovedEvent) -> Self { + fn from_move(e: &MouseMovedEvent) -> Self { match e.pressed_button { Some(b) => match b { gpui::MouseButton::Left => MouseButton::LeftMove, @@ -79,7 +86,7 @@ impl MouseButton { } } - pub fn from_button(e: &MouseButtonEvent) -> Self { + fn from_button(e: &MouseButtonEvent) -> Self { match e.button { gpui::MouseButton::Left => MouseButton::LeftButton, gpui::MouseButton::Right => MouseButton::MiddleButton, @@ -88,7 +95,7 @@ impl MouseButton { } } - pub fn from_scroll(e: &ScrollWheelEvent) -> Self { + fn from_scroll(e: &ScrollWheelEvent) -> Self { if e.delta.y() > 0. { MouseButton::ScrollUp } else { @@ -96,7 +103,7 @@ impl MouseButton { } } - pub fn is_other(&self) -> bool { + fn is_other(&self) -> bool { match self { MouseButton::Other => true, _ => false, @@ -109,24 +116,31 @@ pub fn scroll_report( scroll_lines: i32, e: &ScrollWheelEvent, mode: TermMode, -) -> Option>> { +) -> Option>> { if mode.intersects(TermMode::MOUSE_MODE) && scroll_lines >= 1 { - if let Some(report) = mouse_report( + mouse_report( point, MouseButton::from_scroll(e), true, Modifiers::from_scroll(), MouseFormat::from_mode(mode), - ) { - let mut res = vec![]; - for _ in 0..scroll_lines.abs() { - res.push(report.clone()); - } - return Some(res); - } + ) + .map(|report| repeat(report).take(scroll_lines as usize)) + } else { + None } +} - None +pub fn alt_scroll(scroll_lines: i32) -> Vec { + let cmd = if scroll_lines > 0 { b'A' } else { b'B' }; + + let mut content = Vec::with_capacity(scroll_lines as usize * 3); + for _ in 0..scroll_lines { + content.push(0x1b); + content.push(b'O'); + content.push(cmd); + } + content } pub fn mouse_button_report( @@ -164,6 +178,31 @@ pub fn mouse_moved_report(point: Point, e: &MouseMovedEvent, mode: TermMode) -> } } +pub fn mouse_side(pos: Vector2F, cur_size: TerminalSize) -> alacritty_terminal::index::Direction { + let x = pos.0.x() as usize; + let cell_x = x.saturating_sub(cur_size.cell_width as usize) % cur_size.cell_width as usize; + let half_cell_width = (cur_size.cell_width / 2.0) as usize; + let additional_padding = (cur_size.width() - cur_size.cell_width * 2.) % cur_size.cell_width; + let end_of_grid = cur_size.width() - cur_size.cell_width - additional_padding; + //Width: Pixels or columns? + if cell_x > half_cell_width + // Edge case when mouse leaves the window. + || x as f32 >= end_of_grid + { + Side::Right + } else { + Side::Left + } +} + +pub fn mouse_point(pos: Vector2F, cur_size: TerminalSize, display_offset: usize) -> Point { + let col = pos.x() / cur_size.cell_width; + let col = min(GridCol(col as usize), cur_size.last_column()); + let line = pos.y() / cur_size.line_height; + let line = min(line as i32, cur_size.bottommost_line().0); + Point::new(GridLine(line - display_offset as i32), col) +} + ///Generate the bytes to send to the terminal, from the cell location, a mouse event, and the terminal mode fn mouse_report( point: Point, @@ -246,3 +285,38 @@ fn sgr_mouse_report(point: Point, button: u8, pressed: bool) -> String { msg } + +#[cfg(test)] +mod test { + use crate::mappings::mouse::mouse_point; + + #[test] + fn test_mouse_to_selection() { + let term_width = 100.; + let term_height = 200.; + let cell_width = 10.; + let line_height = 20.; + let mouse_pos_x = 100.; //Window relative + let mouse_pos_y = 100.; //Window relative + let origin_x = 10.; + let origin_y = 20.; + + let cur_size = crate::TerminalSize::new( + line_height, + cell_width, + gpui::geometry::vector::vec2f(term_width, term_height), + ); + + let mouse_pos = gpui::geometry::vector::vec2f(mouse_pos_x, mouse_pos_y); + let origin = gpui::geometry::vector::vec2f(origin_x, origin_y); //Position of terminal window, 1 'cell' in + let mouse_pos = mouse_pos - origin; + let point = mouse_point(mouse_pos, cur_size, 0); + assert_eq!( + point, + alacritty_terminal::index::Point::new( + alacritty_terminal::index::Line(((mouse_pos_y - origin_y) / line_height) as i32), + alacritty_terminal::index::Column(((mouse_pos_x - origin_x) / cell_width) as usize), + ) + ); + } +} diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 37bf85e78f9dd312734c7975ab9527a38582e88a..ff313478c5125172583365c981178950e1aa1114 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -24,16 +24,19 @@ use futures::{ FutureExt, }; -use mappings::mouse::mouse_moved_report; +use mappings::mouse::{ + alt_scroll, mouse_button_report, mouse_moved_report, mouse_point, mouse_side, scroll_report, +}; use modal::deploy_modal; use settings::{Settings, Shell, TerminalBlink}; -use std::{collections::HashMap, fmt::Display, path::PathBuf, sync::Arc, time::Duration}; +use std::{collections::HashMap, fmt::Display, ops::Sub, path::PathBuf, sync::Arc, time::Duration}; use thiserror::Error; use gpui::{ geometry::vector::{vec2f, Vector2F}, keymap::Keystroke, - ClipboardItem, Entity, ModelContext, MouseMovedEvent, MutableAppContext, + ClipboardItem, Entity, ModelContext, MouseButtonEvent, MouseMovedEvent, MutableAppContext, + ScrollWheelEvent, }; use crate::mappings::{ @@ -49,6 +52,11 @@ pub fn init(cx: &mut MutableAppContext) { connected_view::init(cx); } +///Scrolling is unbearably sluggish by default. Alacritty supports a configurable +///Scroll multiplier that is set to 3 by default. This will be removed when I +///Implement scroll bars. +pub const ALACRITTY_SCROLL_MULTIPLIER: f32 = 3.; + const DEBUG_TERMINAL_WIDTH: f32 = 500.; const DEBUG_TERMINAL_HEIGHT: f32 = 30.; const DEBUG_CELL_WIDTH: f32 = 5.; @@ -348,6 +356,7 @@ impl TerminalBuilder { last_mode: TermMode::NONE, cur_size: initial_size, last_mouse: None, + last_offset: 0, }; Ok(TerminalBuilder { @@ -417,6 +426,7 @@ pub struct Terminal { title: String, cur_size: TerminalSize, last_mode: TermMode, + last_offset: usize, last_mouse: Option<(Point, Direction)>, } @@ -509,7 +519,7 @@ impl Terminal { } pub fn input(&mut self, input: String) { - self.scroll(Scroll::Bottom); + self.events.push(InternalEvent::Scroll(Scroll::Bottom)); self.events.push(InternalEvent::SetSelection(None)); self.write_to_pty(input); } @@ -563,11 +573,12 @@ impl Terminal { self.process_terminal_event(&e, &mut term, cx) } - // self.utilization = Self::estimate_utilization(term.take_last_processed_bytes()); self.last_mode = *term.mode(); let content = term.renderable_content(); + self.last_offset = content.display_offset; + let cursor_text = term.grid()[content.cursor.point].c; f(content, cursor_text) @@ -602,23 +613,45 @@ impl Terminal { } } - /// Handle a mouse move - pub fn mouse_move(&mut self, point: Point, side: Direction, e: &MouseMovedEvent) { - if self.mouse_changed(point, side) { + pub fn mouse_mode(&self, shift: bool) -> bool { + self.last_mode.intersects(TermMode::MOUSE_MODE) && !shift + } + + pub fn mouse_move(&mut self, e: &MouseMovedEvent, origin: Vector2F) { + let position = e.position.sub(origin); + + let point = mouse_point(position, self.cur_size, self.last_offset); + let side = mouse_side(position, self.cur_size); + + if self.mouse_changed(point, side) && self.mouse_mode(e.shift) { if let Some(bytes) = mouse_moved_report(point, e, self.last_mode) { self.pty_tx.notify(bytes); } } } - pub fn mouse_drag(&mut self, point: Point, side: Direction) { - self.events - .push(InternalEvent::UpdateSelection((point, side))); + pub fn mouse_drag(&mut self, e: MouseMovedEvent, origin: Vector2F) { + let position = e.position.sub(origin); + + if !self.mouse_mode(e.shift) { + let point = mouse_point(position, self.cur_size, self.last_offset); + let side = mouse_side(position, self.cur_size); + + self.events + .push(InternalEvent::UpdateSelection((point, side))); + } } - pub fn mouse_down(&mut self, point: Point, side: Direction) { - if self.last_mode.intersects(TermMode::MOUSE_REPORT_CLICK) { - //TODE: MOUSE MODE + pub fn mouse_down(&mut self, e: &MouseButtonEvent, origin: Vector2F) { + let position = e.position.sub(origin); + + let point = mouse_point(position, self.cur_size, self.last_offset); + let side = mouse_side(position, self.cur_size); + + if self.mouse_mode(e.shift) { + if let Some(bytes) = mouse_button_report(point, e, true, self.last_mode) { + self.pty_tx.notify(bytes); + } } else { self.events .push(InternalEvent::SetSelection(Some(Selection::new( @@ -629,11 +662,15 @@ impl Terminal { } } - pub fn click(&mut self, point: Point, side: Direction, clicks: usize) { - if self.last_mode.intersects(TermMode::MOUSE_MODE) { - //TODE: MOUSE MODE - } else { - let selection_type = match clicks { + pub fn left_click(&mut self, e: &MouseButtonEvent, origin: Vector2F) { + let position = e.position.sub(origin); + //TODO: Alt-click cursor position + + if !self.mouse_mode(e.shift) { + let point = mouse_point(position, self.cur_size, self.last_offset); + let side = mouse_side(position, self.cur_size); + + let selection_type = match e.click_count { 0 => return, //This is a release 1 => Some(SelectionType::Simple), 2 => Some(SelectionType::Semantic), @@ -648,13 +685,55 @@ impl Terminal { } } - ///Scroll the terminal - pub fn scroll(&mut self, scroll: Scroll) { - if self.last_mode.intersects(TermMode::MOUSE_MODE) { - //TODE: MOUSE MODE + pub fn mouse_up(&mut self, e: &MouseButtonEvent, origin: Vector2F) { + let position = e.position.sub(origin); + + if self.mouse_mode(e.shift) { + let point = mouse_point(position, self.cur_size, self.last_offset); + + if let Some(bytes) = mouse_button_report(point, e, false, self.last_mode) { + self.pty_tx.notify(bytes); + } + } else { + // Seems pretty standard to automatically copy on mouse_up for terminals, + // so let's do that here + self.copy(); } + } - self.events.push(InternalEvent::Scroll(scroll)); + ///Scroll the terminal + pub fn scroll(&mut self, scroll: &ScrollWheelEvent, origin: Vector2F) { + if self.mouse_mode(false) { + //TODO: Currently this only sends the current scroll reports as they come in. Alacritty + //Sends the *entire* scroll delta on *every* scroll event, only resetting it when + //The scroll enters 'TouchPhase::Started'. Do I need to replicate this? + //This would be consistent with a scroll model based on 'distance from origin'... + let scroll_lines = (scroll.delta.y() / self.cur_size.line_height) as i32; + let point = mouse_point(scroll.position.sub(origin), self.cur_size, self.last_offset); + + if let Some(scrolls) = scroll_report(point, scroll_lines as i32, scroll, self.last_mode) + { + for scroll in scrolls { + self.pty_tx.notify(scroll); + } + }; + } else if self + .last_mode + .contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL) + { + //TODO: See above TODO, also applies here. + let scroll_lines = ((scroll.delta.y() * ALACRITTY_SCROLL_MULTIPLIER) + / self.cur_size.line_height) as i32; + + self.pty_tx.notify(alt_scroll(scroll_lines)) + } else { + let scroll_lines = ((scroll.delta.y() * ALACRITTY_SCROLL_MULTIPLIER) + / self.cur_size.line_height) as i32; + if scroll_lines != 0 { + let scroll = Scroll::Delta(scroll_lines); + self.events.push(InternalEvent::Scroll(scroll)); + } + } } }