mirror of
https://github.com/typst/typst
synced 2025-06-15 00:26:26 +08:00
change Repeatable to struct
This commit is contained in:
parent
9139baf263
commit
75a4cfb2e4
@ -274,7 +274,8 @@ impl<'a> GridLayouter<'a> {
|
||||
pub fn layout(mut self, engine: &mut Engine) -> SourceResult<Fragment> {
|
||||
self.measure_columns(engine)?;
|
||||
|
||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||
if let Some(footer) = self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
// Ensure rows in the first region will be aware of the possible
|
||||
// presence of the footer.
|
||||
self.prepare_footer(footer, engine, 0)?;
|
||||
@ -296,7 +297,9 @@ impl<'a> GridLayouter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||
if let Some(footer) =
|
||||
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
if y >= footer.start {
|
||||
if y == footer.start {
|
||||
self.layout_footer(footer, engine, self.finished.len())?;
|
||||
@ -1564,14 +1567,15 @@ impl<'a> GridLayouter<'a> {
|
||||
// TODO(subfooters): explicitly check for short-lived footers.
|
||||
// TODO(subfooters): widow prevention for non-repeated footers with a
|
||||
// similar mechanism / when implementing multiple footers.
|
||||
let footer_would_be_widow =
|
||||
matches!(self.grid.footer, Some(Repeatable::Repeated(_)))
|
||||
&& self.current.lrows.is_empty()
|
||||
&& self.current.could_progress_at_top;
|
||||
let footer_would_be_widow = matches!(&self.grid.footer, Some(footer) if footer.repeated)
|
||||
&& self.current.lrows.is_empty()
|
||||
&& self.current.could_progress_at_top;
|
||||
|
||||
let mut laid_out_footer_start = None;
|
||||
if !footer_would_be_widow {
|
||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||
if let Some(footer) =
|
||||
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
// Don't layout the footer if it would be alone with the header
|
||||
// in the page (hence the widow check), and don't layout it
|
||||
// twice (check below).
|
||||
@ -1735,7 +1739,9 @@ impl<'a> GridLayouter<'a> {
|
||||
self.current.repeating_header_heights.clear();
|
||||
|
||||
let disambiguator = self.finished.len();
|
||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||
if let Some(footer) =
|
||||
self.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
self.prepare_footer(footer, engine, disambiguator)?;
|
||||
}
|
||||
|
||||
|
@ -170,7 +170,7 @@ impl<'a> GridLayouter<'a> {
|
||||
}
|
||||
|
||||
for header in self.pending_headers {
|
||||
if let Repeatable::Repeated(header) = header {
|
||||
if header.repeated {
|
||||
// Vector remains sorted by increasing levels:
|
||||
// - 'pending_headers' themselves are sorted, since we only
|
||||
// push non-mutually-conflicting headers at a time.
|
||||
@ -238,8 +238,8 @@ impl<'a> GridLayouter<'a> {
|
||||
self.current.initial_after_repeats = self.regions.size.y;
|
||||
}
|
||||
|
||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||
if skipped_region {
|
||||
if let Some(footer) = &self.grid.footer {
|
||||
if footer.repeated && skipped_region {
|
||||
// Simulate the footer again; the region's 'full' might have
|
||||
// changed.
|
||||
self.regions.size.y += self.current.footer_height;
|
||||
@ -321,13 +321,13 @@ impl<'a> GridLayouter<'a> {
|
||||
|
||||
let mut has_non_repeated_pending_header = false;
|
||||
for header in self.pending_headers {
|
||||
if matches!(header, Repeatable::NotRepeated(_)) {
|
||||
if !header.repeated {
|
||||
self.current.initial_after_repeats = self.regions.size.y;
|
||||
has_non_repeated_pending_header = true;
|
||||
}
|
||||
let header_height =
|
||||
self.layout_header_rows(header.unwrap(), engine, disambiguator, false)?;
|
||||
if matches!(header, Repeatable::Repeated(_)) {
|
||||
if header.repeated {
|
||||
self.current.repeating_header_height += header_height;
|
||||
self.current.repeating_header_heights.push(header_height);
|
||||
}
|
||||
@ -410,7 +410,7 @@ impl<'a> GridLayouter<'a> {
|
||||
// it is guaranteed this header won't appear in a future
|
||||
// region, so multi-page rows and cells can effectively ignore
|
||||
// this header.
|
||||
if !short_lived && matches!(header, Repeatable::Repeated(_)) {
|
||||
if !short_lived && header.repeated {
|
||||
self.current.repeating_header_height += header_height;
|
||||
self.current.repeating_header_heights.push(header_height);
|
||||
if at_top {
|
||||
@ -519,11 +519,7 @@ impl<'a> GridLayouter<'a> {
|
||||
// anyway, so this is mostly for correctness.
|
||||
self.regions.size.y += self.current.footer_height;
|
||||
|
||||
let repeats = self
|
||||
.grid
|
||||
.footer
|
||||
.as_ref()
|
||||
.is_some_and(|f| matches!(f, Repeatable::Repeated(_)));
|
||||
let repeats = self.grid.footer.as_ref().is_some_and(|f| f.repeated);
|
||||
let footer_len = self.grid.rows.len() - footer.start;
|
||||
self.unbreakable_rows_left += footer_len;
|
||||
|
||||
|
@ -238,8 +238,8 @@ impl GridLayouter<'_> {
|
||||
// current row is dynamic and depends on the amount of upcoming
|
||||
// unbreakable cells (with or without a rowspan setting).
|
||||
let mut amount_unbreakable_rows = None;
|
||||
if let Some(Repeatable::NotRepeated(footer)) = &self.grid.footer {
|
||||
if current_row >= footer.start {
|
||||
if let Some(footer) = &self.grid.footer {
|
||||
if !footer.repeated && current_row >= footer.start {
|
||||
// Non-repeated footer, so keep it unbreakable.
|
||||
//
|
||||
// TODO(subfooters): This will become unnecessary
|
||||
@ -400,7 +400,7 @@ impl GridLayouter<'_> {
|
||||
if breakable
|
||||
&& (!self.repeating_headers.is_empty()
|
||||
|| !self.pending_headers.is_empty()
|
||||
|| matches!(self.grid.footer, Some(Repeatable::Repeated(_))))
|
||||
|| matches!(&self.grid.footer, Some(footer) if footer.repeated))
|
||||
{
|
||||
// Subtract header and footer height from all upcoming regions
|
||||
// when measuring the cell, including the last repeated region.
|
||||
@ -1176,14 +1176,15 @@ impl<'a> RowspanSimulator<'a> {
|
||||
(None, Abs::zero())
|
||||
};
|
||||
|
||||
let footer_height =
|
||||
if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer {
|
||||
layouter
|
||||
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
||||
.height
|
||||
} else {
|
||||
Abs::zero()
|
||||
};
|
||||
let footer_height = if let Some(footer) =
|
||||
layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
layouter
|
||||
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
||||
.height
|
||||
} else {
|
||||
Abs::zero()
|
||||
};
|
||||
|
||||
let mut skipped_region = false;
|
||||
|
||||
@ -1211,7 +1212,9 @@ impl<'a> RowspanSimulator<'a> {
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(Repeatable::Repeated(footer)) = &layouter.grid.footer {
|
||||
if let Some(footer) =
|
||||
layouter.grid.footer.as_ref().and_then(Repeatable::as_repeated)
|
||||
{
|
||||
self.footer_height = if skipped_region {
|
||||
// Simulate footers again, at the new region, as
|
||||
// the full region height may change.
|
||||
|
@ -465,23 +465,23 @@ impl Footer {
|
||||
}
|
||||
}
|
||||
|
||||
/// A possibly repeatable grid child.
|
||||
/// A possibly repeatable grid child (header or footer).
|
||||
///
|
||||
/// It still exists even when not repeatable, but must not have additional
|
||||
/// considerations by grid layout, other than for consistency (such as making
|
||||
/// a certain group of rows unbreakable).
|
||||
pub enum Repeatable<T> {
|
||||
/// The user asked this grid child to repeat.
|
||||
Repeated(T),
|
||||
/// The user asked this grid child to not repeat.
|
||||
NotRepeated(T),
|
||||
pub struct Repeatable<T> {
|
||||
inner: T,
|
||||
|
||||
/// Whether the user requested the child to repeat.
|
||||
pub repeated: bool,
|
||||
}
|
||||
|
||||
impl<T> Deref for Repeatable<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.unwrap()
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,28 +490,23 @@ impl<T> Repeatable<T> {
|
||||
/// it repeats.
|
||||
#[inline]
|
||||
pub fn unwrap(&self) -> &T {
|
||||
match self {
|
||||
Self::Repeated(repeated) => repeated,
|
||||
Self::NotRepeated(not_repeated) => not_repeated,
|
||||
}
|
||||
&self.inner
|
||||
}
|
||||
|
||||
/// Gets the value inside this repeatable, regardless of whether
|
||||
/// it repeats (mutably).
|
||||
#[inline]
|
||||
pub fn unwrap_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
Self::Repeated(repeated) => repeated,
|
||||
Self::NotRepeated(not_repeated) => not_repeated,
|
||||
}
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
/// Returns `Some` if the value is repeated, `None` otherwise.
|
||||
#[inline]
|
||||
pub fn as_repeated(&self) -> Option<&T> {
|
||||
match self {
|
||||
Self::Repeated(repeated) => Some(repeated),
|
||||
Self::NotRepeated(_) => None,
|
||||
if self.repeated {
|
||||
Some(&self.inner)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -906,7 +901,7 @@ impl<'a> CellGrid<'a> {
|
||||
|
||||
#[inline]
|
||||
pub fn has_repeated_headers(&self) -> bool {
|
||||
self.headers.iter().any(|h| matches!(h, Repeatable::Repeated(_)))
|
||||
self.headers.iter().any(|h| h.repeated)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1614,11 +1609,7 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
conflicting_header.unwrap_mut().short_lived = true;
|
||||
}
|
||||
|
||||
headers.push(if row_group.repeat {
|
||||
Repeatable::Repeated(data)
|
||||
} else {
|
||||
Repeatable::NotRepeated(data)
|
||||
});
|
||||
headers.push(Repeatable { inner: data, repeated: row_group.repeat });
|
||||
}
|
||||
|
||||
RowGroupKind::Footer => {
|
||||
@ -1920,10 +1911,9 @@ impl<'x> CellGridResolver<'_, '_, 'x> {
|
||||
// footers.
|
||||
// TODO(subfooters): Switch this to marking the last N
|
||||
// consecutive footers as short lived.
|
||||
if repeat_footer && at_least_one_cell {
|
||||
Repeatable::Repeated(footer)
|
||||
} else {
|
||||
Repeatable::NotRepeated(footer)
|
||||
Repeatable {
|
||||
inner: footer,
|
||||
repeated: repeat_footer && at_least_one_cell,
|
||||
}
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user