From 81d278eaad8662479c9bfc5475f73b9fb84b4feb Mon Sep 17 00:00:00 2001 From: VishnuByrraju Date: Wed, 21 Oct 2026 12:21:40 +0530 Subject: [PATCH] fix(paths): the Work Path is drawn only while selected or a path tool is active (#6551) --- crates/ui-egui/src/path_selection_tests.rs | 4 +- crates/ui-egui/src/vector_ui.rs | 48 ++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/path_selection_tests.rs b/crates/ui-egui/src/path_selection_tests.rs index 12b1670863..a5d4ee035a 100644 --- a/crates/ui-egui/src/path_selection_tests.rs +++ b/crates/ui-egui/src/path_selection_tests.rs @@ -248,7 +248,8 @@ fn clicking_shape_with_path_selection_selects_its_layer() { assert_eq!(h.state().session.active().unwrap().active_layer.unwrap().0, rect_layer); } -/// Work paths remain visible (outline) regardless of the active tool. Before the fix, +/// A work path selected in the Paths panel remains visible (outline) regardless of the active tool +/// (one that is not selected is hidden, #6551). Before the fix, /// `draw_overlay` was gated on `vector_tool` so paths disappeared when switching to Brush, Move, /// etc. This test renders the canvas with a Brush tool active and a work path present, then /// confirms the path's outline pixels are painted in the accent colour, proving the path is drawn. @@ -259,6 +260,7 @@ fn path_overlay_drawn_for_non_vector_tools() { app.sync_views(); // Place a work path whose top edge runs exactly along y=10 in document space. app.run("path.set", json!({"name": "work", "path": rect_path(50.0, 10.0, 100.0, 80.0)})).unwrap(); + app.ui.selected_path = Some("work".into()); // Switch to a non-vector tool — before the fix this hid the path outline. app.ui.tool = Tool::Brush; diff --git a/crates/ui-egui/src/vector_ui.rs b/crates/ui-egui/src/vector_ui.rs index 205e47aaf9..104f514d61 100644 --- a/crates/ui-egui/src/vector_ui.rs +++ b/crates/ui-egui/src/vector_ui.rs @@ -1009,10 +1009,15 @@ pub fn draw_overlay(app: &PhotocraftApp, painter: &egui::Painter, xf: &ViewXform crate::anchor_tools::draw_hover(app, painter, &to_scr, accent, painter.ctx().input(|i| i.modifiers)); } } else if paths { - // Paths remain visible as outlines with any tool. Path Selection and the Pen tools add - // anchor squares; Direct Selection has its own overlay above. + // The shape's or vector mask's path stays visible as an outline with any tool. Path + // Selection and the Pen tools add anchor squares; Direct Selection has its own overlay + // above. The Work Path is drawn only while it is the path selected in the Paths panel or + // a path tool is active, as in Photoshop: a Work Path left unselected (one a PSD arrived + // with, or after Ctrl-click Load as Selection) would otherwise cover the marching ants (#6551). let anchors = shows_anchors(tool); - if let Some(wp) = &doc.work_path { + if let Some(wp) = &doc.work_path + && (anchors || app.ui.selected_path.as_deref() == Some("work")) + { draw_path(wp, anchors); } let st = app.session.active(); @@ -2069,6 +2074,43 @@ mod tests { assert!(!shows_anchors(Tool::Brush) && !shows_anchors(Tool::Move)); } + #[test] + fn an_unselected_work_path_is_not_drawn_over_the_canvas() { + // #6551: Ctrl-click Load as Selection leaves the Paths panel's selection alone, yet the Work + // Path stayed drawn over the new selection's edge. Photoshop draws it only while selected + // in the Paths panel (or a path tool is active). + let ctx = egui::Context::default(); + let mut app = app(); + let path = json!({"subpaths": [{"closed": true, "knots": [ + {"anchor": [20, 20], "in": [20, 20], "out": [20, 20]}, + {"anchor": [90, 20], "in": [90, 20], "out": [90, 20]}, + {"anchor": [90, 90], "in": [90, 90], "out": [90, 90]} + ]}]}); + app.run("path.set", json!({"name": "work", "path": path})).unwrap(); + app.run("path.toSelection", json!({"name": "work", "mode": "replace"})).unwrap(); + assert!(app.ui.selected_path.is_none()); + for tool in [Tool::Move, Tool::Brush, Tool::Rectangle, Tool::Zoom] { + app.ui.tool = tool; + assert_eq!(overlay_shapes(&app, &ctx), 0, "{tool:?}: an unselected Work Path stays off the canvas"); + } + // Selected in the Paths panel: drawn with any tool. + app.ui.selected_path = Some("work".into()); + for tool in [Tool::Move, Tool::Brush] { + app.ui.tool = tool; + assert!(overlay_shapes(&app, &ctx) > 0, "{tool:?}: the selected Work Path is drawn"); + } + // Another path selected: the Work Path is not the target path. + app.ui.selected_path = Some("Saved".into()); + app.ui.tool = Tool::Move; + assert_eq!(overlay_shapes(&app, &ctx), 0); + // A path tool shows the Work Path it edits even when the panel selection was cleared. + app.ui.selected_path = None; + for tool in [Tool::Pen, Tool::PathSelection] { + app.ui.tool = tool; + assert!(overlay_shapes(&app, &ctx) > 0, "{tool:?}: path tools draw the Work Path"); + } + } + #[test] fn show_target_path_and_extras_hide_the_path_outlines() { // #1119: View › Show › Target Path only flipped its checkmark; the canvas kept drawing the