diff --git a/crates/editor/src/cursor_animation.rs b/crates/editor/src/cursor_animation.rs index 0ea173c1e7..79a9faeae5 100644 --- a/crates/editor/src/cursor_animation.rs +++ b/crates/editor/src/cursor_animation.rs @@ -598,6 +598,35 @@ fn nearly_equal(left: f32, right: f32) -> bool { (left - right).abs() <= GEOMETRY_EPSILON } +pub(crate) fn animated_corners_overlap_target( + target_bounds: Bounds, + corners: &[Point; 4], +) -> bool { + let min_x = corners + .iter() + .map(|p| p.x) + .min() + .expect("the corners argument is a 4 item array, which should always have an x min"); + let max_x = corners + .iter() + .map(|p| p.x) + .max() + .expect("the corners argument is a 4 item array, which should always have an x max"); + let min_y = corners + .iter() + .map(|p| p.y) + .min() + .expect("the corners argument is a 4 item array, which should always have an y min"); + let max_y = corners + .iter() + .map(|p| p.y) + .max() + .expect("the corners argument is a 4 item array, which should always have an x max"); + let animated_bounds = Bounds::from_corners(point(min_x, min_y), point(max_x, max_y)); + + animated_bounds.intersects(&target_bounds) +} + #[cfg(test)] mod tests { use super::*; @@ -870,6 +899,57 @@ mod tests { ); } + #[test] + fn one_cell_movement_overlaps_target_only_after_advancing() { + let now = Instant::now(); + let mut state = CursorAnimationState::default(); + let target = bounds_with_width(8.0, 0.0, 8.0); + state.update( + logical_position(0, 0), + bounds_with_width(0.0, 0.0, 8.0), + viewport(0.0), + now, + ); + + let corners = state + .update(logical_position(0, 1), target, viewport(0.0), now) + .unwrap(); + assert!(!animated_corners_overlap_target(target, &corners)); + + let corners = state + .update( + logical_position(0, 1), + target, + viewport(0.0), + now + Duration::from_millis(16), + ) + .unwrap(); + assert!(animated_corners_overlap_target(target, &corners)); + + let mut vertical_state = CursorAnimationState::default(); + let vertical_target = bounds_with_width(0.0, 20.0, 8.0); + vertical_state.update( + logical_position(0, 0), + bounds_with_width(0.0, 0.0, 8.0), + viewport(0.0), + now, + ); + let corners = vertical_state + .update(logical_position(1, 0), vertical_target, viewport(0.0), now) + .unwrap(); + assert!(!animated_corners_overlap_target(vertical_target, &corners)); + + let corners = vertical_state + .update( + logical_position(1, 0), + vertical_target, + viewport(0.0), + now + Duration::from_millis(16), + ) + .unwrap(); + assert!(animated_corners_overlap_target(vertical_target, &corners)); + } + #[test] fn geometry_change_without_logical_movement_snaps() { let now = Instant::now(); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index f58057c803..0320af6ab8 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -17,7 +17,7 @@ use crate::{ SelectionDragState, SizingBehavior, SoftWrap, ToPoint, code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP}, column_pixels, - cursor_animation::{CursorViewport, LogicalCursorPosition}, + cursor_animation::{CursorViewport, LogicalCursorPosition, animated_corners_overlap_target}, display_map::{ Block, BlockContext, BlockStyle, ChunkRendererId, DisplaySnapshot, EditorMargins, HighlightKey, HighlightedChunk, ToDisplayPoint, @@ -11092,6 +11092,8 @@ impl CursorLayout { } pub fn paint(&mut self, origin: gpui::Point, window: &mut Window, cx: &mut App) { + let bounds = window.pixel_snap_bounds(self.bounds(origin)); + if let Some(corners) = self.animated_corners { let mut builder = gpui::PathBuilder::fill(); builder.add_polygon(&corners, true); @@ -11100,25 +11102,26 @@ impl CursorLayout { name.paint(window, cx); } window.paint_path(path, self.color); - return; + + if !animated_corners_overlap_target(bounds, &corners) { + return; + } } - } - - let bounds = window.pixel_snap_bounds(self.bounds(origin)); - - //Draw background or border quad - let cursor = if matches!(self.shape, CursorShape::Hollow) { - outline(bounds, self.color, BorderStyle::Solid) } else { - fill(bounds, self.color) - }; + //Draw background or border quad + let cursor = if matches!(self.shape, CursorShape::Hollow) { + outline(bounds, self.color, BorderStyle::Solid) + } else { + fill(bounds, self.color) + }; - if let Some(name) = &mut self.cursor_name { - name.paint(window, cx); + if let Some(name) = &mut self.cursor_name { + name.paint(window, cx); + } + + window.paint_quad(cursor); } - window.paint_quad(cursor); - if let Some(block_text) = &self.block_text { block_text .paint(