Add gap and justify parameters to repeat (#4644)

Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
Eric Biedert 2024-08-15 22:21:42 +02:00 committed by GitHub
parent d221a89a40
commit 4853726e5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 43 additions and 13 deletions

View File

@ -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<RepeatElem> {
@ -56,15 +65,6 @@ fn layout_repeat(
) -> SourceResult<Frame> {
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;
}
}

BIN
tests/ref/repeat-gap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

View File

@ -42,3 +42,18 @@ A#box(width: 1fr, repeat(rect(width: 6em, height: 0.7em)))B
// Error: 2:2-2:13 repeat with no size restrictions
#set page(width: auto)
#repeat(".")
--- repeat-gap ---
// Test repeat with custom gap.
A#box(width: 1fr, repeat(rect(width: 2em, height: 1em), gap: 1em))B
--- repeat-no-justify ---
// Test repeat with disabled justification.
#set repeat(justify: false)
A#box(width: 1fr, repeat(rect(width: 2em, height: 1em), gap: 1em))B
--- repeat-no-justify-align ---
// Test repeat with alignment and disabled justification.
#set repeat(justify: false)
#set align(right)
A#box(width: 1fr, repeat(rect(width: 2em, height: 1em), gap: 1em))B