diff --git a/crates/doc/src/pattern.rs b/crates/doc/src/pattern.rs index 74bdf0514..ac00a6206 100644 --- a/crates/doc/src/pattern.rs +++ b/crates/doc/src/pattern.rs @@ -279,7 +279,7 @@ impl PatternDef { out } /// Offsets of the pattern-editing preview copies (`copies`×`copies` around the tile, the - /// centre `(0, 0)` excluded). + /// centre `(0, 0)` excluded), in row-major order (not paint order). pub fn preview_offsets(&self) -> Vec { let k = (self.copies.clamp(1, 15) / 2) as i64; let mut out = vec![]; @@ -292,6 +292,21 @@ impl PatternDef { } out } + /// Offsets of every pattern-editing preview copy, including the centre tile, in the same paint + /// order [`offsets_covering`] uses for [`Overlap`]. + pub fn preview_offsets_in_paint_order(&self) -> Vec { + let k = (self.copies.clamp(1, 15) / 2) as i64; + let (i0, i1, j0, j1) = (-k, k, -k, k); + let mut out = vec![]; + let rows: Vec = if self.overlap.bottom_in_front { (j0..=j1).collect() } else { (j0..=j1).rev().collect() }; + for &j in &rows { + let cols: Vec = if self.overlap.right_in_front { (i0..=i1).collect() } else { (i0..=i1).rev().collect() }; + for i in cols { + out.push(self.offset(i, j)); + } + } + out + } /// Instances covering `region` (document space) as plain nodes for a pattern painted with /// `paint_xf` (pattern space → document), fresh-id-less (id 0). Used by exporters and Distort /// Pattern Fills; Expand uses [`Self::instances_in_with`]. @@ -744,6 +759,17 @@ mod tests { } } + #[test] + fn preview_paint_order_respects_overlap() { + let mut def = PatternDef::new("p", vec![sq(0.0, 0.0, 10.0)]); + def.copies = 3; + assert!(close(*def.preview_offsets_in_paint_order().last().unwrap(), Vec2::new(-10.0, -10.0))); + let mut d2 = def.clone(); + d2.overlap = Overlap { right_in_front: true, bottom_in_front: true }; + assert!(close(*d2.preview_offsets_in_paint_order().last().unwrap(), Vec2::new(10.0, 10.0))); + assert_eq!(def.preview_offsets_in_paint_order().len(), 9); + } + #[test] fn covering_offsets_and_overlap_order() { let def = PatternDef::new("p", vec![sq(0.0, 0.0, 10.0)]); diff --git a/crates/render/src/pattern.rs b/crates/render/src/pattern.rs index e1c7c2901..29c788a13 100644 --- a/crates/render/src/pattern.rs +++ b/crates/render/src/pattern.rs @@ -308,17 +308,23 @@ impl Renderer { let children: Vec> = layer.children().cloned().unwrap_or_default(); if layer.visible && !children.is_empty() { let dim = (def.dim_copies / 100.0).clamp(0.0, 1.0); - let comp = crate::group::Composite { opacity: dim, ..Default::default() }; - self.group(ctx, f, comp, &mut |r, c, fr| { - for o in def.preview_offsets() { - let frame = Frame { view: fr.view * Affine::translate(o), visible: fr.visible - o, ..*fr }; - for a in &children { - r.draw_arc(c, &frame, a); - } + for o in def.preview_offsets_in_paint_order() { + let is_center = o.x == 0.0 && o.y == 0.0; + if is_center { + self.draw_arc(ctx, f, layer); + } else { + let comp = crate::group::Composite { opacity: dim, ..Default::default() }; + self.group(ctx, f, comp, &mut |r, c, fr| { + let frame = Frame { view: fr.view * Affine::translate(o), visible: fr.visible - o, ..*fr }; + for a in &children { + r.draw_arc(c, &frame, a); + } + }); } - }); + } + } else { + self.draw_arc(ctx, f, layer); } - self.draw_arc(ctx, f, layer); // The tile edge and swatch bounds are editing aids: exports and thumbnails leave them out, // as they do guides (#3261). if f.opts.skip_templates {