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