mirror of
https://github.com/typst/typst
synced 2025-07-02 02:02:53 +08:00
begin refactoring layout_headers
- May have to include ALL headers when skipping a region... - Approach too naive
This commit is contained in:
parent
6029e6f3bb
commit
0143d0775b
@ -1,3 +1,4 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use typst_library::diag::SourceResult;
|
use typst_library::diag::SourceResult;
|
||||||
use typst_library::engine::Engine;
|
use typst_library::engine::Engine;
|
||||||
@ -146,12 +147,26 @@ impl<'a> GridLayouter<'a> {
|
|||||||
/// footers.
|
/// footers.
|
||||||
pub fn layout_headers(
|
pub fn layout_headers(
|
||||||
&mut self,
|
&mut self,
|
||||||
headers: &[&Header],
|
headers: impl Clone + IntoIterator<Item = &'a Header>,
|
||||||
|
include_repeating: bool,
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
disambiguator: usize,
|
|
||||||
) -> SourceResult<()> {
|
) -> SourceResult<()> {
|
||||||
let header_height =
|
// Generate different locations for content in headers across its
|
||||||
self.simulate_header_height(&self.regions, engine, disambiguator)?;
|
// repetitions by assigning a unique number for each one.
|
||||||
|
let disambiguator = self.finished.len();
|
||||||
|
// At first, only consider the height of the given headers. However,
|
||||||
|
// for upcoming regions, we will have to consider repeating headers as
|
||||||
|
// well.
|
||||||
|
let mut header_height = self.simulate_header_height(
|
||||||
|
headers.clone(),
|
||||||
|
&self.regions,
|
||||||
|
engine,
|
||||||
|
disambiguator,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// We already take the footer into account below.
|
||||||
|
// While skipping regions, footer height won't be automatically
|
||||||
|
// re-calculated until the end.
|
||||||
let mut skipped_region = false;
|
let mut skipped_region = false;
|
||||||
while self.unbreakable_rows_left == 0
|
while self.unbreakable_rows_left == 0
|
||||||
&& !self.regions.size.y.fits(header_height + self.footer_height)
|
&& !self.regions.size.y.fits(header_height + self.footer_height)
|
||||||
@ -161,26 +176,58 @@ impl<'a> GridLayouter<'a> {
|
|||||||
// header and the footer.
|
// header and the footer.
|
||||||
self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]);
|
self.finish_region_internal(Frame::soft(Axes::splat(Abs::zero())), vec![]);
|
||||||
skipped_region = true;
|
skipped_region = true;
|
||||||
|
|
||||||
|
header_height = if include_repeating {
|
||||||
|
// Laying out pending headers, so we have to consider the
|
||||||
|
// combined height of already repeating headers as well.
|
||||||
|
self.simulate_header_height(
|
||||||
|
self.repeating_headers.iter().map(|h| *h).chain(headers.clone()),
|
||||||
|
&self.regions,
|
||||||
|
engine,
|
||||||
|
disambiguator,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
self.simulate_header_height(
|
||||||
|
headers.clone(),
|
||||||
|
&self.regions,
|
||||||
|
engine,
|
||||||
|
disambiguator,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simulate the footer again; the region's 'full' might have
|
||||||
|
// changed.
|
||||||
|
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
||||||
|
self.footer_height = self
|
||||||
|
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
||||||
|
.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we also take the footer into account for remaining space.
|
||||||
|
self.regions.size.y -= self.footer_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the header height for this region.
|
// Reset the header height for this region.
|
||||||
// It will be re-calculated when laying out each header row.
|
// It will be re-calculated when laying out each header row.
|
||||||
self.header_height = Abs::zero();
|
self.header_height = Abs::zero();
|
||||||
|
|
||||||
if let Some(Repeatable::Repeated(footer)) = &self.grid.footer {
|
let trivial_vector = vec![];
|
||||||
if skipped_region {
|
let repeating_header_prefix =
|
||||||
// Simulate the footer again; the region's 'full' might have
|
if include_repeating { &self.repeating_headers } else { &trivial_vector };
|
||||||
// changed.
|
|
||||||
self.footer_height = self
|
|
||||||
.simulate_footer(footer, &self.regions, engine, disambiguator)?
|
|
||||||
.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group of headers is unbreakable.
|
// Group of headers is unbreakable.
|
||||||
// Thus, no risk of 'finish_region' being recursively called from
|
// Thus, no risk of 'finish_region' being recursively called from
|
||||||
// within 'layout_row'.
|
// within 'layout_row'.
|
||||||
self.unbreakable_rows_left += total_header_row_count(headers);
|
self.unbreakable_rows_left +=
|
||||||
|
total_header_row_count(repeating_header_prefix.iter().map(Deref::deref))
|
||||||
|
+ total_header_row_count(headers.clone());
|
||||||
|
let mut i = 0;
|
||||||
|
while let Some(header) = repeating_header_prefix.get(i) {
|
||||||
|
for y in header.range() {
|
||||||
|
self.layout_row(y, engine, disambiguator)?;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
for header in headers {
|
for header in headers {
|
||||||
for y in header.range() {
|
for y in header.range() {
|
||||||
self.layout_row(y, engine, disambiguator)?;
|
self.layout_row(y, engine, disambiguator)?;
|
||||||
@ -190,9 +237,9 @@ impl<'a> GridLayouter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the total expected height of several headers.
|
/// Calculates the total expected height of several headers.
|
||||||
pub fn simulate_header_height(
|
pub fn simulate_header_height<'h: 'a>(
|
||||||
&self,
|
&self,
|
||||||
headers: &[&Header],
|
headers: impl IntoIterator<Item = &'h Header>,
|
||||||
regions: &Regions<'_>,
|
regions: &Regions<'_>,
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
disambiguator: usize,
|
disambiguator: usize,
|
||||||
@ -307,6 +354,8 @@ impl<'a> GridLayouter<'a> {
|
|||||||
|
|
||||||
/// The total amount of rows in the given list of headers.
|
/// The total amount of rows in the given list of headers.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn total_header_row_count(headers: &[&Header]) -> usize {
|
pub fn total_header_row_count<'h>(
|
||||||
headers.iter().map(|h| h.end - h.start).sum()
|
headers: impl IntoIterator<Item = &'h Header>,
|
||||||
|
) -> usize {
|
||||||
|
headers.into_iter().map(|h| h.end - h.start).sum()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user