From 4853726e5b55ea5861566e850db3e6260879d9f8 Mon Sep 17 00:00:00 2001 From: Eric Biedert Date: Thu, 15 Aug 2024 22:21:42 +0200 Subject: [PATCH] Add `gap` and `justify` parameters to `repeat` (#4644) Co-authored-by: Laurenz --- crates/typst/src/layout/repeat.rs | 41 ++++++++++++++++++-------- tests/ref/repeat-gap.png | Bin 0 -> 293 bytes tests/ref/repeat-no-justify-align.png | Bin 0 -> 246 bytes tests/ref/repeat-no-justify.png | Bin 0 -> 246 bytes tests/suite/layout/repeat.typ | 15 ++++++++++ 5 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 tests/ref/repeat-gap.png create mode 100644 tests/ref/repeat-no-justify-align.png create mode 100644 tests/ref/repeat-no-justify.png diff --git a/crates/typst/src/layout/repeat.rs b/crates/typst/src/layout/repeat.rs index 30fc314da..60a3e4c7e 100644 --- a/crates/typst/src/layout/repeat.rs +++ b/crates/typst/src/layout/repeat.rs @@ -5,7 +5,7 @@ use crate::foundations::{ }; use crate::introspection::Locator; use crate::layout::{ - Abs, AlignElem, Axes, BlockElem, Frame, Point, Region, Regions, Size, + Abs, AlignElem, Axes, BlockElem, Frame, Length, Point, Region, Regions, Size, }; use crate::utils::Numeric; @@ -14,7 +14,7 @@ use crate::utils::Numeric; /// This can be useful when implementing a custom index, reference, or outline. /// /// Space may be inserted between the instances of the body parameter, so be -/// sure to include negative space if you need the instances to overlap. +/// sure to adjust the [`justify`]($repeat.justify) parameter accordingly. /// /// Errors if there no bounds on the available space, as it would create /// infinite content. @@ -35,6 +35,15 @@ pub struct RepeatElem { /// The content to repeat. #[required] pub body: Content, + + /// The gap between each instance of the body. + #[default] + pub gap: Length, + + /// Whether to increase the gap between instances to completely fill the + /// available space. + #[default(true)] + pub justify: bool, } impl Show for Packed { @@ -56,15 +65,6 @@ fn layout_repeat( ) -> SourceResult { let pod = Regions::one(region.size, Axes::new(false, false)); let piece = elem.body().layout(engine, locator, styles, pod)?.into_frame(); - - let align = AlignElem::alignment_in(styles).resolve(styles); - - let fill = region.size.x; - let width = piece.width(); - let count = (fill / width).floor(); - let remaining = fill % width; - let apart = remaining / (count - 1.0); - let size = Size::new(region.size.x, piece.height()); if !size.is_finite() { @@ -76,15 +76,30 @@ fn layout_repeat( frame.set_baseline(piece.baseline()); } + let mut gap = elem.gap(styles).resolve(styles); + let fill = region.size.x; + let width = piece.width(); + + // count * width + (count - 1) * gap = fill, but count is an integer so + // we need to round down and get the remainder. + let count = ((fill + gap) / (width + gap)).floor(); + let remaining = (fill + gap) % (width + gap); + + let justify = elem.justify(styles); + if justify { + gap += remaining / (count - 1.0); + } + + let align = AlignElem::alignment_in(styles).resolve(styles); let mut offset = Abs::zero(); - if count == 1.0 { + if count == 1.0 || !justify { offset += align.x.position(remaining); } if width > Abs::zero() { for _ in 0..(count as usize).min(1000) { frame.push_frame(Point::with_x(offset), piece.clone()); - offset += piece.width() + apart; + offset += piece.width() + gap; } } diff --git a/tests/ref/repeat-gap.png b/tests/ref/repeat-gap.png new file mode 100644 index 0000000000000000000000000000000000000000..40f7f29ac8216928b81926b08c6adbd158450c14 GIT binary patch literal 293 zcmV+=0owkFP)=?I6@W|04>2U#sReir`Vii1REhXI4xfJmu42b_s(1L7MI2E40qDb#|mHWnc}i| z_Q_b~~|8@Vj_)0sA7Y6p>uy}LD)Q}}K^zncHRoE>q{r~^IC(SI@`|-cO z4y(nTZm<8J5_9orzyN3kNDZb6v;qWEfu9Rc+sf>hSS|kd4~YMNtH%WGD2_jjMa6Cu r6}?zgeE9!&w00V`c+}!ii>U(us3to6c#+$J00000NkvXXu0mjf!}5YG literal 0 HcmV?d00001 diff --git a/tests/ref/repeat-no-justify-align.png b/tests/ref/repeat-no-justify-align.png new file mode 100644 index 0000000000000000000000000000000000000000..1cb79736e1b6d8e5ee8a9beb8583d218b2a88fdd GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^6+kS<0VEg>Eo$`yQhPmJ978H@CI7H@Xh^*BD6rdI zS8ku!chiI>f05Hd+ba4hZP`9_FOHeE;poX5M>HnN&JkPx$J@C3ZuN8B%I?#T%G<0n zpC`BKfA=YjwE3N)^H#^~$IsJ(?MMIb`X61hbna1Z=HCSodv+#eoe+}x^<)2ktv6!R z|NXDOKRHe8_1_=&zkjE0gD4ZP1VaeN1l`w%E^jmXts2(-|1WcrLQBKF tDxVL68h-2EwEwSn&t498^0IY?lB4 literal 0 HcmV?d00001 diff --git a/tests/ref/repeat-no-justify.png b/tests/ref/repeat-no-justify.png new file mode 100644 index 0000000000000000000000000000000000000000..820aec09d68279017c0fa6bc05bd228f3a4eb559 GIT binary patch literal 246 zcmV@J?RmDw+`TKw-H5dZ&H wj|tl0YQB>x3o`ldXzes=@u