mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Add gap
and justify
parameters to repeat
(#4644)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
parent
d221a89a40
commit
4853726e5b
@ -5,7 +5,7 @@ use crate::foundations::{
|
|||||||
};
|
};
|
||||||
use crate::introspection::Locator;
|
use crate::introspection::Locator;
|
||||||
use crate::layout::{
|
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;
|
use crate::utils::Numeric;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ use crate::utils::Numeric;
|
|||||||
/// This can be useful when implementing a custom index, reference, or outline.
|
/// 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
|
/// 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
|
/// Errors if there no bounds on the available space, as it would create
|
||||||
/// infinite content.
|
/// infinite content.
|
||||||
@ -35,6 +35,15 @@ pub struct RepeatElem {
|
|||||||
/// The content to repeat.
|
/// The content to repeat.
|
||||||
#[required]
|
#[required]
|
||||||
pub body: Content,
|
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> {
|
impl Show for Packed<RepeatElem> {
|
||||||
@ -56,15 +65,6 @@ fn layout_repeat(
|
|||||||
) -> SourceResult<Frame> {
|
) -> SourceResult<Frame> {
|
||||||
let pod = Regions::one(region.size, Axes::new(false, false));
|
let pod = Regions::one(region.size, Axes::new(false, false));
|
||||||
let piece = elem.body().layout(engine, locator, styles, pod)?.into_frame();
|
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());
|
let size = Size::new(region.size.x, piece.height());
|
||||||
|
|
||||||
if !size.is_finite() {
|
if !size.is_finite() {
|
||||||
@ -76,15 +76,30 @@ fn layout_repeat(
|
|||||||
frame.set_baseline(piece.baseline());
|
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();
|
let mut offset = Abs::zero();
|
||||||
if count == 1.0 {
|
if count == 1.0 || !justify {
|
||||||
offset += align.x.position(remaining);
|
offset += align.x.position(remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
if width > Abs::zero() {
|
if width > Abs::zero() {
|
||||||
for _ in 0..(count as usize).min(1000) {
|
for _ in 0..(count as usize).min(1000) {
|
||||||
frame.push_frame(Point::with_x(offset), piece.clone());
|
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
BIN
tests/ref/repeat-gap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 293 B |
BIN
tests/ref/repeat-no-justify-align.png
Normal file
BIN
tests/ref/repeat-no-justify-align.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 246 B |
BIN
tests/ref/repeat-no-justify.png
Normal file
BIN
tests/ref/repeat-no-justify.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 246 B |
@ -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
|
// Error: 2:2-2:13 repeat with no size restrictions
|
||||||
#set page(width: auto)
|
#set page(width: auto)
|
||||||
#repeat(".")
|
#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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user