From 2305ebb931cd16c3e2a3bed2ded4f1b735d624b1 Mon Sep 17 00:00:00 2001 From: Mirko Kerezovic Date: Tue, 20 Oct 2026 21:01:51 +0200 Subject: [PATCH] Fix Show and Hide Guides (#3219) --- crates/render/src/lib.rs | 10 +++++++--- crates/render/src/tests_layeropts.rs | 20 ++++++++++++++++++++ crates/ui-egui/src/canvas.rs | 23 ++++++++++++++++++++++- crates/ui-egui/src/lib.rs | 4 +++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/crates/render/src/lib.rs b/crates/render/src/lib.rs index 442e156cb..c8f800693 100644 --- a/crates/render/src/lib.rs +++ b/crates/render/src/lib.rs @@ -125,6 +125,9 @@ pub struct RenderOptions { pub skip_templates: bool, /// View › Hide Template: template layers left out of the screen view (guides stay). pub hide_templates: bool, + /// View › Hide Guides: paths made into guides left out of the screen view. Exports use + /// `skip_templates`, which independently leaves both templates and guides out. + pub hide_guides: bool, /// Pattern editing mode's tile edge and swatch bounds colour (Object → Pattern → Tile Edge /// Color), RGB. pub tile_edge: [u8; 3], @@ -246,6 +249,7 @@ impl Default for RenderOptions { trim: false, skip_templates: false, hide_templates: false, + hide_guides: false, tile_edge: vectorcraft_doc::LAYER_COLORS[0].1, guide: ([0x4a, 0xd8, 0xff], false), mask_view: None, @@ -1036,9 +1040,9 @@ impl Renderer { /// Whether `a` is left out of this frame: hidden, a skipped template or guide, or culled. fn skipped(&mut self, f: &Frame, a: &Arc) -> bool { - let skipped_template = (f.opts.skip_templates || f.opts.hide_templates) && matches!(a.kind, NodeKind::Layer { template: true, .. }) - || f.opts.skip_templates && matches!(a.kind, NodeKind::Path { guide: true, .. }); - if !a.visible || skipped_template || f.opts.hidden.contains(&a.id) { + let skipped_view_item = (f.opts.skip_templates || f.opts.hide_templates) && matches!(a.kind, NodeKind::Layer { template: true, .. }) + || (f.opts.skip_templates || f.opts.hide_guides) && matches!(a.kind, NodeKind::Path { guide: true, .. }); + if !a.visible || skipped_view_item || f.opts.hidden.contains(&a.id) { return true; } match self.bounds_of(f.symbols, a) { diff --git a/crates/render/src/tests_layeropts.rs b/crates/render/src/tests_layeropts.rs index ffac0cd3c..7130d654b 100644 --- a/crates/render/src/tests_layeropts.rs +++ b/crates/render/src/tests_layeropts.rs @@ -166,3 +166,23 @@ fn guides_draw_on_screen_only() { assert!(drawn(false) > 0, "on screen the guide shows"); assert_eq!(drawn(true), 0, "exports leave it out"); } + +/// #3219: View > Hide Guides hides paths made into guides without using the export/template +/// filtering switch; Show Guides (the default) draws them again. +#[test] +fn hide_guides_hides_guide_paths_on_screen() { + let mut d = Document::new(100.0, 100.0); + let l = d.layers[0].id; + let mut g = Node::path(d.alloc_id(), shapes::rectangle(Rect::new(70.0, 70.0, 90.0, 90.0)), Appearance::default()); + if let NodeKind::Path { guide, .. } = &mut g.kind { + *guide = true; + } + d.insert(Some(l), 0, g).unwrap(); + let pixels = |hide_guides: bool| { + let opts = RenderOptions { background: Some([255; 4]), hide_guides, ..Default::default() }; + let r = Renderer::new().render(&d, 100, 100, Affine::IDENTITY, &opts); + (60..100).flat_map(|y| (60..100).map(move |x| (x, y))).filter(|&(x, y)| r.pixel(x, y) != [255; 4]).count() + }; + assert!(pixels(false) > 0, "Show Guides draws the guide path"); + assert_eq!(pixels(true), 0, "Hide Guides leaves the guide path out"); +} diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index b87ff3f60..d800b2713 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -330,6 +330,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { outline: app.ui.view.outline, trim: app.ui.view.trim_view, templates: app.ui.view.templates, + guides: app.ui.view.guides, ppp, hidden: vec![], rot: v.rotation, @@ -383,6 +384,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { overprint_preview: vectorcraft_render::proof::overprint_preview_on(), trim: app.ui.view.trim_view, hide_templates: !app.ui.view.templates, + hide_guides: !app.ui.view.guides, tile_edge: vectorcraft_color::Color::from_hex(&app.session.prefs.pattern_tile_edge_color).map_or(opts.tile_edge, |c| { let [r, g, b, _] = c.to_rgba8(1.0); [r, g, b] @@ -1951,7 +1953,7 @@ fn hit_with( path_only: prefs.object_selection_by_path_only, type_path_only: prefs.type_selection_by_path_only, scope: app.session.active().and_then(|st| st.isolation), - ..Default::default() + skip_guides: !app.ui.view.guides, }; test(&app.session.active()?.doc, p, opt) } @@ -5630,6 +5632,25 @@ mod tests { /// Smart Guides › Object Highlighting (#394): the outline of the object under the pointer does not /// show with View › Snap to Grid or View › Pixel Preview on, even with Smart Guides and the option on. + /// #3219: guide paths hidden by View > Hide Guides are not hittable and cannot reveal + /// themselves through Smart Guides object highlighting. + #[test] + fn hidden_guide_paths_have_no_hover_highlight() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 400, "height": 300})).unwrap(); + let id = app.run("shape.rectangle", json!({"x": 100, "y": 100, "width": 100, "height": 100})).unwrap()["id"].as_u64().unwrap(); + app.run("view.guides.make", json!({})).unwrap(); + app.run("select.none", json!({})).unwrap(); + app.select_tool("selection"); + app.ui.view.guides = false; + let ctx = egui::Context::default(); + frame(&mut app, &ctx, vec![]); + let xf = Xf::new(app.canvas_rect.unwrap(), app.view().unwrap()); + let color = c32(app.session.active().unwrap().doc.layer_color(vectorcraft_doc::NodeId(id))); + frame(&mut app, &ctx, vec![egui::Event::PointerMoved(xf.to_screen(Point::new(100.0, 150.0)))]); + assert!(drawn_in(&mut app, &ctx, color, 1.5).is_empty(), "a hidden guide has no hover highlight"); + } + #[test] fn snap_to_grid_and_pixel_preview_hide_the_hover_outline() { let mut app = VectorcraftApp::new(Session::new(), Default::default()); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 7d63c21a8..59efd1bcd 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -354,8 +354,10 @@ pub struct CacheKey { pub h: u32, pub outline: bool, pub trim: bool, - /// View › Hide Template: template layers left out ([`vectorcraft_render::RenderOptions::skip_templates`]). + /// View › Hide Template: template layers left out ([`vectorcraft_render::RenderOptions::hide_templates`]). pub templates: bool, + /// View › Show/Hide Guides: whether guide paths are visible in the artwork raster. + pub guides: bool, pub ppp: f32, pub hidden: Vec, pub rot: f64,