mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Extract regions into separate module
This commit is contained in:
parent
ebbee6274c
commit
697ae1f925
@ -14,6 +14,7 @@ mod pad;
|
||||
mod page;
|
||||
mod par;
|
||||
mod place;
|
||||
mod regions;
|
||||
mod repeat;
|
||||
mod spacing;
|
||||
mod stack;
|
||||
@ -34,6 +35,7 @@ pub use self::pad::*;
|
||||
pub use self::page::*;
|
||||
pub use self::par::*;
|
||||
pub use self::place::*;
|
||||
pub use self::regions::*;
|
||||
pub use self::repeat::*;
|
||||
pub use self::spacing::*;
|
||||
pub use self::stack::*;
|
||||
@ -45,7 +47,6 @@ use std::mem;
|
||||
|
||||
use typed_arena::Arena;
|
||||
use typst::diag::SourceResult;
|
||||
use typst::geom::*;
|
||||
use typst::model::{
|
||||
applicable, capability, realize, Content, Node, SequenceNode, Style, StyleChain,
|
||||
StyleVecBuilder, StyledNode,
|
||||
@ -147,126 +148,6 @@ impl Layout for Content {
|
||||
#[capability]
|
||||
pub trait Inline: Layout {}
|
||||
|
||||
/// A sequence of regions to layout into.
|
||||
#[derive(Copy, Clone, Hash)]
|
||||
pub struct Regions<'a> {
|
||||
/// The (remaining) size of the first region.
|
||||
pub first: Size,
|
||||
/// The base size for relative sizing.
|
||||
pub base: Size,
|
||||
/// The height of followup regions. The width is the same for all regions.
|
||||
pub backlog: &'a [Abs],
|
||||
/// The height of the final region that is repeated once the backlog is
|
||||
/// drained. The width is the same for all regions.
|
||||
pub last: Option<Abs>,
|
||||
/// Whether nodes should expand to fill the regions instead of shrinking to
|
||||
/// fit the content.
|
||||
pub expand: Axes<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Regions<'a> {
|
||||
/// Create a new region sequence with exactly one region.
|
||||
pub fn one(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
backlog: &[],
|
||||
last: None,
|
||||
expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new sequence of same-size regions that repeats indefinitely.
|
||||
pub fn repeat(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
backlog: &[],
|
||||
last: Some(size.y),
|
||||
expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new regions where all sizes are mapped with `f`.
|
||||
///
|
||||
/// Note that since all regions must have the same width, the width returned
|
||||
/// by `f` is ignored for the backlog and the final region.
|
||||
pub fn map<'v, F>(&self, backlog: &'v mut Vec<Abs>, mut f: F) -> Regions<'v>
|
||||
where
|
||||
F: FnMut(Size) -> Size,
|
||||
{
|
||||
let x = self.first.x;
|
||||
backlog.clear();
|
||||
backlog.extend(self.backlog.iter().map(|&y| f(Size::new(x, y)).y));
|
||||
Regions {
|
||||
first: f(self.first),
|
||||
base: f(self.base),
|
||||
backlog,
|
||||
last: self.last.map(|y| f(Size::new(x, y)).y),
|
||||
expand: self.expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the first region is full and a region break is called for.
|
||||
pub fn is_full(&self) -> bool {
|
||||
Abs::zero().fits(self.first.y) && !self.in_last()
|
||||
}
|
||||
|
||||
/// Whether the first region is the last usable region.
|
||||
///
|
||||
/// If this is true, calling `next()` will have no effect.
|
||||
pub fn in_last(&self) -> bool {
|
||||
self.backlog.is_empty() && self.last.map_or(true, |height| self.first.y == height)
|
||||
}
|
||||
|
||||
/// Advance to the next region if there is any.
|
||||
pub fn next(&mut self) {
|
||||
if let Some(height) = self
|
||||
.backlog
|
||||
.split_first()
|
||||
.map(|(first, tail)| {
|
||||
self.backlog = tail;
|
||||
*first
|
||||
})
|
||||
.or(self.last)
|
||||
{
|
||||
self.first.y = height;
|
||||
self.base.y = height;
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that returns the sizes of the first and all following
|
||||
/// regions, equivalently to what would be produced by calling
|
||||
/// [`next()`](Self::next) repeatedly until all regions are exhausted.
|
||||
/// This iterator may be infinite.
|
||||
pub fn iter(&self) -> impl Iterator<Item = Size> + '_ {
|
||||
let first = std::iter::once(self.first);
|
||||
let backlog = self.backlog.iter();
|
||||
let last = self.last.iter().cycle();
|
||||
first.chain(backlog.chain(last).map(|&h| Size::new(self.first.x, h)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Regions<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Regions ")?;
|
||||
let mut list = f.debug_list();
|
||||
let mut prev = self.first.y;
|
||||
list.entry(&self.first);
|
||||
for &height in self.backlog {
|
||||
list.entry(&Size::new(self.first.x, height));
|
||||
prev = height;
|
||||
}
|
||||
if let Some(last) = self.last {
|
||||
if last != prev {
|
||||
list.entry(&Size::new(self.first.x, last));
|
||||
}
|
||||
list.entry(&(..));
|
||||
}
|
||||
list.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Realize into a node that is capable of root-level layout.
|
||||
fn realize_root<'a>(
|
||||
vt: &mut Vt,
|
||||
|
123
library/src/layout/regions.rs
Normal file
123
library/src/layout/regions.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use typst::geom::{Abs, Axes, Size};
|
||||
|
||||
/// A sequence of regions to layout into.
|
||||
#[derive(Copy, Clone, Hash)]
|
||||
pub struct Regions<'a> {
|
||||
/// The (remaining) size of the first region.
|
||||
pub first: Size,
|
||||
/// The base size for relative sizing.
|
||||
pub base: Size,
|
||||
/// The height of followup regions. The width is the same for all regions.
|
||||
pub backlog: &'a [Abs],
|
||||
/// The height of the final region that is repeated once the backlog is
|
||||
/// drained. The width is the same for all regions.
|
||||
pub last: Option<Abs>,
|
||||
/// Whether nodes should expand to fill the regions instead of shrinking to
|
||||
/// fit the content.
|
||||
pub expand: Axes<bool>,
|
||||
}
|
||||
|
||||
impl<'a> Regions<'a> {
|
||||
/// Create a new region sequence with exactly one region.
|
||||
pub fn one(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
backlog: &[],
|
||||
last: None,
|
||||
expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new sequence of same-size regions that repeats indefinitely.
|
||||
pub fn repeat(size: Size, base: Size, expand: Axes<bool>) -> Self {
|
||||
Self {
|
||||
first: size,
|
||||
base,
|
||||
backlog: &[],
|
||||
last: Some(size.y),
|
||||
expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create new regions where all sizes are mapped with `f`.
|
||||
///
|
||||
/// Note that since all regions must have the same width, the width returned
|
||||
/// by `f` is ignored for the backlog and the final region.
|
||||
pub fn map<'v, F>(&self, backlog: &'v mut Vec<Abs>, mut f: F) -> Regions<'v>
|
||||
where
|
||||
F: FnMut(Size) -> Size,
|
||||
{
|
||||
let x = self.first.x;
|
||||
backlog.clear();
|
||||
backlog.extend(self.backlog.iter().map(|&y| f(Size::new(x, y)).y));
|
||||
Regions {
|
||||
first: f(self.first),
|
||||
base: f(self.base),
|
||||
backlog,
|
||||
last: self.last.map(|y| f(Size::new(x, y)).y),
|
||||
expand: self.expand,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the first region is full and a region break is called for.
|
||||
pub fn is_full(&self) -> bool {
|
||||
Abs::zero().fits(self.first.y) && !self.in_last()
|
||||
}
|
||||
|
||||
/// Whether the first region is the last usable region.
|
||||
///
|
||||
/// If this is true, calling `next()` will have no effect.
|
||||
pub fn in_last(&self) -> bool {
|
||||
self.backlog.is_empty() && self.last.map_or(true, |height| self.first.y == height)
|
||||
}
|
||||
|
||||
/// Advance to the next region if there is any.
|
||||
pub fn next(&mut self) {
|
||||
if let Some(height) = self
|
||||
.backlog
|
||||
.split_first()
|
||||
.map(|(first, tail)| {
|
||||
self.backlog = tail;
|
||||
*first
|
||||
})
|
||||
.or(self.last)
|
||||
{
|
||||
self.first.y = height;
|
||||
self.base.y = height;
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that returns the sizes of the first and all following
|
||||
/// regions, equivalently to what would be produced by calling
|
||||
/// [`next()`](Self::next) repeatedly until all regions are exhausted.
|
||||
/// This iterator may be infinite.
|
||||
pub fn iter(&self) -> impl Iterator<Item = Size> + '_ {
|
||||
let first = std::iter::once(self.first);
|
||||
let backlog = self.backlog.iter();
|
||||
let last = self.last.iter().cycle();
|
||||
first.chain(backlog.chain(last).map(|&h| Size::new(self.first.x, h)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Regions<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("Regions ")?;
|
||||
let mut list = f.debug_list();
|
||||
let mut prev = self.first.y;
|
||||
list.entry(&self.first);
|
||||
for &height in self.backlog {
|
||||
list.entry(&Size::new(self.first.x, height));
|
||||
prev = height;
|
||||
}
|
||||
if let Some(last) = self.last {
|
||||
if last != prev {
|
||||
list.entry(&Size::new(self.first.x, last));
|
||||
}
|
||||
list.entry(&(..));
|
||||
}
|
||||
list.finish()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user