mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46: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 page;
|
||||||
mod par;
|
mod par;
|
||||||
mod place;
|
mod place;
|
||||||
|
mod regions;
|
||||||
mod repeat;
|
mod repeat;
|
||||||
mod spacing;
|
mod spacing;
|
||||||
mod stack;
|
mod stack;
|
||||||
@ -34,6 +35,7 @@ pub use self::pad::*;
|
|||||||
pub use self::page::*;
|
pub use self::page::*;
|
||||||
pub use self::par::*;
|
pub use self::par::*;
|
||||||
pub use self::place::*;
|
pub use self::place::*;
|
||||||
|
pub use self::regions::*;
|
||||||
pub use self::repeat::*;
|
pub use self::repeat::*;
|
||||||
pub use self::spacing::*;
|
pub use self::spacing::*;
|
||||||
pub use self::stack::*;
|
pub use self::stack::*;
|
||||||
@ -45,7 +47,6 @@ use std::mem;
|
|||||||
|
|
||||||
use typed_arena::Arena;
|
use typed_arena::Arena;
|
||||||
use typst::diag::SourceResult;
|
use typst::diag::SourceResult;
|
||||||
use typst::geom::*;
|
|
||||||
use typst::model::{
|
use typst::model::{
|
||||||
applicable, capability, realize, Content, Node, SequenceNode, Style, StyleChain,
|
applicable, capability, realize, Content, Node, SequenceNode, Style, StyleChain,
|
||||||
StyleVecBuilder, StyledNode,
|
StyleVecBuilder, StyledNode,
|
||||||
@ -147,126 +148,6 @@ impl Layout for Content {
|
|||||||
#[capability]
|
#[capability]
|
||||||
pub trait Inline: Layout {}
|
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.
|
/// Realize into a node that is capable of root-level layout.
|
||||||
fn realize_root<'a>(
|
fn realize_root<'a>(
|
||||||
vt: &mut Vt,
|
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