summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2018-03-13 19:00:14 +0100
committerJoe Wilm <jwilm@users.noreply.github.com>2018-03-13 16:58:15 -0700
commit6173603677c950d96c470aa609dbc07e7d4c792f (patch)
treefebd084c4ce293e7288d9704c3f1c74f1c2dadeb
parentf8e36d166342d9ee4a91f8e89f55677cd0fd0644 (diff)
Fix multi-line selection with single cell end
When the user selected multiple lines, dragging the selection downwards, and then leaves the cursor to the left side of the first cell, the first cell was still incorrectly selected. This has been fixed. The selection also did not update if the mouse was outside of the window, now all movement events are accpeted even when the mouse is outside of the window. This allows updating the selection when the user is dragging the cursor too far. Mouse movement and click events outside of the window are not propagated, these are only used for updating the selection.
-rw-r--r--src/event.rs12
-rw-r--r--src/input.rs61
-rw-r--r--src/selection.rs27
-rw-r--r--src/term/mod.rs22
4 files changed, 71 insertions, 51 deletions
diff --git a/src/event.rs b/src/event.rs
index af5053f4..c079ddfb 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -154,8 +154,8 @@ pub enum ClickState {
/// State of the mouse
pub struct Mouse {
- pub x: u32,
- pub y: u32,
+ pub x: usize,
+ pub y: usize,
pub left_button_state: ElementState,
pub last_click_timestamp: Instant,
pub click_state: ClickState,
@@ -311,13 +311,11 @@ impl<N: Notify> Processor<N> {
processor.ctx.terminal.dirty = true;
},
CursorMoved { position: (x, y), modifiers, .. } => {
- let x = x as i32;
- let y = y as i32;
- let x = limit(x, 0, processor.ctx.size_info.width as i32);
- let y = limit(y, 0, processor.ctx.size_info.height as i32);
+ let x = limit(x as i32, 0, processor.ctx.size_info.width as i32);
+ let y = limit(y as i32, 0, processor.ctx.size_info.height as i32);
*hide_cursor = false;
- processor.mouse_moved(x as u32, y as u32, modifiers);
+ processor.mouse_moved(x as usize, y as usize, modifiers);
},
MouseWheel { delta, phase, modifiers, .. } => {
*hide_cursor = false;
diff --git a/src/input.rs b/src/input.rs
index af45c6ef..def20b4d 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -262,44 +262,43 @@ impl From<&'static str> for Action {
impl<'a, A: ActionContext + 'a> Processor<'a, A> {
#[inline]
- pub fn mouse_moved(&mut self, x: u32, y: u32, modifiers: ModifiersState) {
+ pub fn mouse_moved(&mut self, x: usize, y: usize, modifiers: ModifiersState) {
self.ctx.mouse_mut().x = x;
self.ctx.mouse_mut().y = y;
let size_info = self.ctx.size_info();
- if let Some(point) = size_info.pixels_to_coords(x as usize, y as usize) {
- let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line);
- let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col);
+ let point = size_info.pixels_to_coords(x, y);
- let cell_x = (x as usize - size_info.padding_x as usize) % size_info.cell_width as usize;
- let half_cell_width = (size_info.cell_width / 2.0) as usize;
+ let prev_line = mem::replace(&mut self.ctx.mouse_mut().line, point.line);
+ let prev_col = mem::replace(&mut self.ctx.mouse_mut().column, point.col);
- let cell_side = if cell_x > half_cell_width
- // Edge case when mouse leaves the window
- || x as f32 >= size_info.width - size_info.padding_x
+ let cell_x = x.saturating_sub(size_info.padding_x as usize) % size_info.cell_width as usize;
+ let half_cell_width = (size_info.cell_width / 2.0) as usize;
+
+ let cell_side = if cell_x > half_cell_width
+ // Edge case when mouse leaves the window
+ || x as f32 >= size_info.width - size_info.padding_x
+ {
+ Side::Right
+ } else {
+ Side::Left
+ };
+ self.ctx.mouse_mut().cell_side = cell_side;
+
+ if self.ctx.mouse_mut().left_button_state == ElementState::Pressed {
+ let report_mode = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION;
+ if modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode) {
+ self.ctx.update_selection(Point {
+ line: point.line,
+ col: point.col
+ }, cell_side);
+ } else if self.ctx.terminal_mode().contains(mode::TermMode::MOUSE_MOTION)
+ // Only report motion when changing cells
+ && (prev_line != self.ctx.mouse_mut().line
+ || prev_col != self.ctx.mouse_mut().column)
+ && size_info.contains_point(x, y)
{
- Side::Right
- } else {
- Side::Left
- };
- self.ctx.mouse_mut().cell_side = cell_side;
-
- if self.ctx.mouse_mut().left_button_state == ElementState::Pressed {
- let report_mode = mode::TermMode::MOUSE_REPORT_CLICK | mode::TermMode::MOUSE_MOTION;
- if modifiers.shift || !self.ctx.terminal_mode().intersects(report_mode) {
- self.ctx.update_selection(Point {
- line: point.line,
- col: point.col
- }, cell_side);
- } else if self.ctx.terminal_mode().contains(mode::TermMode::MOUSE_MOTION)
- // Only report motion when changing cells
- && (
- prev_line != self.ctx.mouse_mut().line
- || prev_col != self.ctx.mouse_mut().column
- )
- {
- self.mouse_report(32, ElementState::Pressed);
- }
+ self.mouse_report(32, ElementState::Pressed);
}
}
}
diff --git a/src/selection.rs b/src/selection.rs
index 8e7fa29b..d49236a4 100644
--- a/src/selection.rs
+++ b/src/selection.rs
@@ -253,8 +253,31 @@ impl Selection {
// Handle some edge cases
if start.line > end.line {
- start.col += 1;
- end.col -= 1;
+ if end.col > Column(0) {
+ start.col += 1;
+ end.col -= 1;
+ }
+ // Special case for when a multi-line selection to the
+ // bottom ends on a new line with just one cell selected
+ // and the first cell should not be selected
+ else {
+ if start_side == Side::Right {
+ start.col += 1;
+ }
+
+ // Remove the single selected cell if mouse left window
+ if end_side == Side::Left {
+ end.line += 1;
+ end.col = cols - 1;
+ }
+
+ return Some(Span {
+ cols,
+ front: end,
+ tail: start,
+ ty: SpanType::Inclusive,
+ });
+ }
} else if start.line < end.line {
start.col -= 1;
end.col += 1;
diff --git a/src/term/mod.rs b/src/term/mod.rs
index 511d6fbd..a721501a 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -790,25 +790,21 @@ impl SizeInfo {
Column(((self.width - 2. * self.padding_x) / self.cell_width) as usize)
}
- fn contains_point(&self, x: usize, y:usize) -> bool {
+ pub fn contains_point(&self, x: usize, y:usize) -> bool {
x <= (self.width - self.padding_x) as usize &&
x >= self.padding_x as usize &&
y <= (self.height - self.padding_y) as usize &&
y >= self.padding_y as usize
}
- pub fn pixels_to_coords(&self, x: usize, y: usize) -> Option<Point> {
- if !self.contains_point(x, y) {
- return None;
- }
+ pub fn pixels_to_coords(&self, x: usize, y: usize) -> Point {
+ let col = Column(x.saturating_sub(self.padding_x as usize) / (self.cell_width as usize));
+ let line = Line(y.saturating_sub(self.padding_y as usize) / (self.cell_height as usize));
- let col = Column((x - self.padding_x as usize) / (self.cell_width as usize));
- let line = Line((y - self.padding_y as usize) / (self.cell_height as usize));
-
- Some(Point {
+ Point {
line: min(line, self.lines() - 1),
col: min(col, self.cols() - 1)
- })
+ }
}
}
@@ -1034,7 +1030,11 @@ impl Term {
///
/// Returns None if the coordinates are outside the screen
pub fn pixels_to_coords(&self, x: usize, y: usize) -> Option<Point> {
- self.size_info().pixels_to_coords(x, y)
+ if self.size_info.contains_point(x, y) {
+ Some(self.size_info.pixels_to_coords(x, y))
+ } else {
+ None
+ }
}
/// Access to the raw grid data structure