summaryrefslogtreecommitdiff
path: root/src/library/flow.rs
diff options
context:
space:
mode:
authorMartin <mhaug@live.de>2021-12-22 20:37:34 +0100
committerGitHub <noreply@github.com>2021-12-22 20:37:34 +0100
commitf6c7a8292dc1ab0560408fca9d74505e9d7cf13a (patch)
treebadd3076f6146cec34c55764600df5124c408521 /src/library/flow.rs
parent738ff7e1f573bef678932b313be9969a17af8d22 (diff)
parent438255519e88bb790480306b9a9b452aaf054519 (diff)
Merge pull request #51 from typst/set-rules
Set rules
Diffstat (limited to 'src/library/flow.rs')
-rw-r--r--src/library/flow.rs118
1 files changed, 65 insertions, 53 deletions
diff --git a/src/library/flow.rs b/src/library/flow.rs
index 98b518b7..cfa761b6 100644
--- a/src/library/flow.rs
+++ b/src/library/flow.rs
@@ -1,50 +1,14 @@
use std::fmt::{self, Debug, Formatter};
use super::prelude::*;
-use super::{AlignNode, ParNode, PlacedNode, Spacing};
-
-/// `flow`: A vertical flow of paragraphs and other layout nodes.
-pub fn flow(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
- enum Child {
- Spacing(Spacing),
- Any(Template),
- }
-
- castable! {
- Child,
- Expected: "linear, fractional or template",
- Value::Length(v) => Self::Spacing(Spacing::Linear(v.into())),
- Value::Relative(v) => Self::Spacing(Spacing::Linear(v.into())),
- Value::Linear(v) => Self::Spacing(Spacing::Linear(v)),
- Value::Fractional(v) => Self::Spacing(Spacing::Fractional(v)),
- Value::Template(v) => Self::Any(v),
- }
-
- let children: Vec<Child> = args.all().collect();
-
- Ok(Value::Template(Template::from_block(move |style| {
- let children = children
- .iter()
- .map(|child| match child {
- Child::Spacing(spacing) => FlowChild::Spacing(*spacing),
- Child::Any(node) => FlowChild::Node(node.pack(style)),
- })
- .collect();
-
- FlowNode { children }
- })))
-}
+use super::{AlignNode, ParNode, PlacedNode, SpacingKind, SpacingNode, TextNode};
/// A vertical flow of content consisting of paragraphs and other layout nodes.
///
/// This node is reponsible for layouting both the top-level content flow and
/// the contents of boxes.
-#[derive(Debug, Hash)]
-pub struct FlowNode {
- /// The children that compose the flow. There are different kinds of
- /// children for different purposes.
- pub children: Vec<FlowChild>,
-}
+#[derive(Hash)]
+pub struct FlowNode(pub Vec<FlowChild>);
impl Layout for FlowNode {
fn layout(
@@ -56,19 +20,54 @@ impl Layout for FlowNode {
}
}
+impl Debug for FlowNode {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ f.write_str("Flow ")?;
+ f.debug_list().entries(&self.0).finish()
+ }
+}
+
/// A child of a flow node.
#[derive(Hash)]
pub enum FlowChild {
+ /// A paragraph/block break.
+ Break(Styles),
/// Vertical spacing between other children.
- Spacing(Spacing),
+ Spacing(SpacingNode),
/// An arbitrary node.
Node(PackedNode),
}
+impl FlowChild {
+ /// A reference to the child's styles.
+ pub fn styles(&self) -> &Styles {
+ match self {
+ Self::Break(styles) => styles,
+ Self::Spacing(node) => &node.styles,
+ Self::Node(node) => &node.styles,
+ }
+ }
+
+ /// A mutable reference to the child's styles.
+ pub fn styles_mut(&mut self) -> &mut Styles {
+ match self {
+ Self::Break(styles) => styles,
+ Self::Spacing(node) => &mut node.styles,
+ Self::Node(node) => &mut node.styles,
+ }
+ }
+}
+
impl Debug for FlowChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
- Self::Spacing(spacing) => spacing.fmt(f),
+ Self::Break(styles) => {
+ if f.alternate() {
+ styles.fmt(f)?;
+ }
+ write!(f, "Break")
+ }
+ Self::Spacing(node) => node.fmt(f),
Self::Node(node) => node.fmt(f),
}
}
@@ -118,7 +117,7 @@ impl<'a> FlowLayouter<'a> {
regions.expand.y = false;
Self {
- children: &flow.children,
+ children: &flow.0,
expand,
full,
regions,
@@ -132,15 +131,21 @@ impl<'a> FlowLayouter<'a> {
/// Layout all children.
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
for child in self.children {
- match *child {
- FlowChild::Spacing(Spacing::Linear(v)) => {
- self.layout_absolute(v);
- }
- FlowChild::Spacing(Spacing::Fractional(v)) => {
- self.items.push(FlowItem::Fractional(v));
- self.fr += v;
+ match child {
+ FlowChild::Break(styles) => {
+ let chain = styles.chain(&ctx.styles);
+ let em = chain.get(TextNode::SIZE).abs;
+ let amount = chain.get(ParNode::SPACING).resolve(em);
+ self.layout_absolute(amount.into());
}
- FlowChild::Node(ref node) => {
+ FlowChild::Spacing(node) => match node.kind {
+ SpacingKind::Linear(v) => self.layout_absolute(v),
+ SpacingKind::Fractional(v) => {
+ self.items.push(FlowItem::Fractional(v));
+ self.fr += v;
+ }
+ },
+ FlowChild::Node(node) => {
if self.regions.is_full() {
self.finish_region();
}
@@ -166,18 +171,25 @@ impl<'a> FlowLayouter<'a> {
/// Layout a node.
fn layout_node(&mut self, ctx: &mut LayoutContext, node: &PackedNode) {
+ // Placed nodes that are out of flow produce placed items which aren't
+ // aligned later.
if let Some(placed) = node.downcast::<PlacedNode>() {
- let frame = node.layout(ctx, &self.regions).remove(0);
if placed.out_of_flow() {
+ let frame = node.layout(ctx, &self.regions).remove(0);
self.items.push(FlowItem::Placed(frame.item));
return;
}
}
+ // How to align the node.
let aligns = Spec::new(
// For non-expanding paragraphs it is crucial that we align the
// whole paragraph according to its internal alignment.
- node.downcast::<ParNode>().map_or(Align::Left, |par| par.align),
+ if node.is::<ParNode>() {
+ node.styles.chain(&ctx.styles).get(ParNode::ALIGN)
+ } else {
+ Align::Left
+ },
// Vertical align node alignment is respected by the flow node.
node.downcast::<AlignNode>()
.and_then(|aligned| aligned.aligns.y)
@@ -235,7 +247,7 @@ impl<'a> FlowLayouter<'a> {
output.push_frame(pos, frame);
}
FlowItem::Placed(frame) => {
- output.push_frame(Point::with_y(offset), frame);
+ output.push_frame(Point::zero(), frame);
}
}
}