diff --git a/crates/tools/src/builder.rs b/crates/tools/src/builder.rs index 5a8d44d400..f5be7ac4c5 100644 --- a/crates/tools/src/builder.rs +++ b/crates/tools/src/builder.rs @@ -695,6 +695,14 @@ impl Tool for ShapeBuilderTool { self.finish_edit(cx) } + /// The pointer hovers nothing for the tool: its highlight, the stroke a click would split and + /// the cursor swatch preview go, and a map that arrives afterwards highlights nothing. + fn hover_ended(&mut self, _cx: &ToolContext) { + self.hover = None; + self.stroke = None; + self.at = None; + } + fn poll(&mut self, cx: &ToolContext, wait: bool) -> Vec { let mut acts = self.poll_merge(cx, wait); if !acts.is_empty() || self.dragging { diff --git a/crates/tools/src/builder/live_paint.rs b/crates/tools/src/builder/live_paint.rs index 2ae2f082ee..e5f696a5a7 100644 --- a/crates/tools/src/builder/live_paint.rs +++ b/crates/tools/src/builder/live_paint.rs @@ -769,6 +769,11 @@ impl Tool for LivePaintSelectionTool { vec![] } + /// The pointer hovers nothing for the tool: its highlight goes. + fn hover_ended(&mut self, _cx: &ToolContext) { + self.hover = LpHover::None; + } + fn overlays(&self, cx: &ToolContext) -> Vec { if let Some(r) = self.drag.and_then(|d| d.marquee(cx)) { return vec![Overlay::Marquee(r)]; diff --git a/crates/tools/src/builder/tests.rs b/crates/tools/src/builder/tests.rs index 01b64ee8c3..90e4832771 100644 --- a/crates/tools/src/builder/tests.rs +++ b/crates/tools/src/builder/tests.rs @@ -920,6 +920,43 @@ fn shape_builder_shift_drag_shows_no_scissors_or_stroke_highlight() { assert_eq!(t.cursor(&cx, Point::new(75.0, 75.0), shift), Cursor::ShapeBuilder); } +/// When the pointer leaves the canvas, the Shape Builder's region or stroke highlight and its +/// cursor swatch preview go. +#[test] +fn shape_builder_hover_ended_drops_the_highlight_and_the_swatch_preview() { + let (d, s) = corner_rects(); + let p = paint(); + let cx = cx(&d, &s, &p); + let mut t = ShapeBuilderTool::default(); + for (key, v) in [("pickColorFrom", json!("swatches")), ("cursorSwatchPreview", json!(true)), ("clickStrokeSplitsPath", json!(true))] { + t.set_option(key, &v); + } + // Over a region, then over a stroke a click would split. + for (x, y) in [(25.0, 25.0), (-1.0, 25.0)] { + t.pointer(&cx, &ev(PointerKind::Move, x, y)); + let ov = t.overlays(&cx); + assert!(ov.iter().any(|o| matches!(o, Overlay::Swatch { .. })) && ov.iter().any(|o| matches!(o, Overlay::Path { .. })), "{ov:?}"); + t.hover_ended(&cx); + assert!(t.overlays(&cx).is_empty()); + } +} + +/// A map of a large selection that arrives after the pointer leaves the canvas highlights nothing +/// under the point where the pointer was last seen. +#[test] +fn shape_builder_map_arriving_after_hover_ended_highlights_nothing() { + let (d, s) = square_row(40); + let p = paint(); + let cx = ToolContext { revision: (1, 1), ..cx(&d, &s, &p) }; + let mut t = ShapeBuilderTool::default(); + t.pointer(&cx, &ev(PointerKind::Move, 15.0, 10.0)); + assert!(t.waiting() && t.hover.is_none(), "the map is built on another thread"); + t.hover_ended(&cx); + t.poll(&cx, true); + assert!(!t.waiting()); + assert!(t.hover.is_none() && t.overlays(&cx).is_empty(), "{:?}", t.hover); +} + #[test] fn shape_builder_stroke_options_round_trip_and_pick_the_side_under_the_pointer() { let (d, s) = corner_rects(); @@ -1593,6 +1630,21 @@ fn live_paint_selection_hover_builds_no_map_of_the_selection() { assert!(!t.waiting()); } +/// When the pointer leaves the canvas, the Live Paint Selection tool's highlight goes. +#[test] +fn live_paint_selection_hover_ended_drops_the_highlight() { + let (d, ..) = live_group_doc(); + let s = Selection::default(); + let p = paint(); + let cx = cx(&d, &s, &p); + let mut t = LivePaintSelectionTool::default(); + t.pointer(&cx, &ev(PointerKind::Move, 75.0, 25.0)); + let ov = t.overlays(&cx); + assert!(ov.iter().any(|o| matches!(o, Overlay::Path { .. })), "{ov:?}"); + t.hover_ended(&cx); + assert!(t.overlays(&cx).is_empty()); +} + /// A Live Paint Selection click pressed with `down`: the press does nothing, and the release does /// what is returned. fn lp_click(t: &mut LivePaintSelectionTool, cx: &ToolContext, down: PointerEvent) -> Vec {