summaryrefslogtreecommitdiff
path: root/src/library/layout
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-30 14:12:28 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-30 14:12:28 +0200
commitf9e115daf54c29358f890b137f50a33a781af680 (patch)
tree496de52246629ea8039db6beea94eb779ed2851d /src/library/layout
parentf7c67cde72e6a67f45180856b332bae9863243bd (diff)
New block spacing model
Diffstat (limited to 'src/library/layout')
-rw-r--r--src/library/layout/align.rs12
-rw-r--r--src/library/layout/columns.rs5
-rw-r--r--src/library/layout/flow.rs41
-rw-r--r--src/library/layout/pad.rs12
-rw-r--r--src/library/layout/page.rs4
-rw-r--r--src/library/layout/spacing.rs45
-rw-r--r--src/library/layout/stack.rs12
7 files changed, 91 insertions, 40 deletions
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs
index 2a4d039e..c050d2a4 100644
--- a/src/library/layout/align.rs
+++ b/src/library/layout/align.rs
@@ -13,9 +13,15 @@ pub struct AlignNode {
#[node]
impl AlignNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
- let aligns: Spec<_> = args.find()?.unwrap_or_default();
- let body: LayoutNode = args.expect("body")?;
- Ok(Content::block(body.aligned(aligns)))
+ let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default();
+ let body: Content = args.expect("body")?;
+ Ok(match (body, aligns) {
+ (Content::Block(node), _) => Content::Block(node.aligned(aligns)),
+ (other, Spec { x: Some(x), y: None }) => {
+ other.styled(ParNode::ALIGN, HorizontalAlign(x))
+ }
+ (other, _) => Content::Block(other.pack().aligned(aligns)),
+ })
}
}
diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs
index 4963043e..8e523694 100644
--- a/src/library/layout/columns.rs
+++ b/src/library/layout/columns.rs
@@ -106,7 +106,8 @@ pub struct ColbreakNode;
#[node]
impl ColbreakNode {
- fn construct(_: &mut Context, _: &mut Args) -> TypResult<Content> {
- Ok(Content::Colbreak)
+ fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
+ let weak = args.named("weak")?.unwrap_or(false);
+ Ok(Content::Colbreak { weak })
}
}
diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs
index 6b43c8b7..6193a68f 100644
--- a/src/library/layout/flow.rs
+++ b/src/library/layout/flow.rs
@@ -1,3 +1,5 @@
+use std::cmp::Ordering;
+
use super::{AlignNode, PlaceNode, Spacing};
use crate::library::prelude::*;
use crate::library::text::ParNode;
@@ -10,18 +12,14 @@ use crate::library::text::ParNode;
pub struct FlowNode(pub StyleVec<FlowChild>);
/// A child of a flow node.
-#[derive(Hash)]
+#[derive(Hash, PartialEq)]
pub enum FlowChild {
- /// Leading between other children.
- Leading,
- /// A paragraph / block break.
- Parbreak,
- /// A column / region break.
- Colbreak,
/// Vertical spacing between other children.
Spacing(Spacing),
/// An arbitrary block-level node.
Node(LayoutNode),
+ /// A column / region break.
+ Colbreak,
}
impl Layout for FlowNode {
@@ -36,25 +34,15 @@ impl Layout for FlowNode {
for (child, map) in self.0.iter() {
let styles = map.chain(&styles);
match child {
- FlowChild::Leading => {
- let amount = styles.get(ParNode::LEADING);
- layouter.layout_spacing(amount.into(), styles);
- }
- FlowChild::Parbreak => {
- let leading = styles.get(ParNode::LEADING);
- let spacing = styles.get(ParNode::SPACING);
- let amount = leading + spacing;
- layouter.layout_spacing(amount.into(), styles);
- }
- FlowChild::Colbreak => {
- layouter.finish_region();
- }
FlowChild::Spacing(kind) => {
layouter.layout_spacing(*kind, styles);
}
FlowChild::Node(ref node) => {
layouter.layout_node(ctx, node, styles)?;
}
+ FlowChild::Colbreak => {
+ layouter.finish_region();
+ }
}
}
@@ -72,11 +60,18 @@ impl Debug for FlowNode {
impl Debug for FlowChild {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
- Self::Leading => f.pad("Leading"),
- Self::Parbreak => f.pad("Parbreak"),
- Self::Colbreak => f.pad("Colbreak"),
Self::Spacing(kind) => write!(f, "{:?}", kind),
Self::Node(node) => node.fmt(f),
+ Self::Colbreak => f.pad("Colbreak"),
+ }
+ }
+}
+
+impl PartialOrd for FlowChild {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ match (self, other) {
+ (Self::Spacing(a), Self::Spacing(b)) => a.partial_cmp(b),
+ _ => None,
}
}
}
diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs
index e688e423..2be21bcb 100644
--- a/src/library/layout/pad.rs
+++ b/src/library/layout/pad.rs
@@ -13,12 +13,12 @@ pub struct PadNode {
impl PadNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
let all = args.find()?;
- let hor = args.named("horizontal")?;
- let ver = args.named("vertical")?;
- let left = args.named("left")?.or(hor).or(all).unwrap_or_default();
- let top = args.named("top")?.or(ver).or(all).unwrap_or_default();
- let right = args.named("right")?.or(hor).or(all).unwrap_or_default();
- let bottom = args.named("bottom")?.or(ver).or(all).unwrap_or_default();
+ let x = args.named("x")?;
+ let y = args.named("y")?;
+ let left = args.named("left")?.or(x).or(all).unwrap_or_default();
+ let top = args.named("top")?.or(y).or(all).unwrap_or_default();
+ let right = args.named("right")?.or(x).or(all).unwrap_or_default();
+ let bottom = args.named("bottom")?.or(y).or(all).unwrap_or_default();
let body: LayoutNode = args.expect("body")?;
let padding = Sides::new(left, top, right, bottom);
Ok(Content::block(body.padded(padding)))
diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs
index 8e5801ea..4307d2f9 100644
--- a/src/library/layout/page.rs
+++ b/src/library/layout/page.rs
@@ -165,8 +165,8 @@ pub struct PagebreakNode;
#[node]
impl PagebreakNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
- let soft = args.named("soft")?.unwrap_or(false);
- Ok(Content::Pagebreak(soft))
+ let weak = args.named("weak")?.unwrap_or(false);
+ Ok(Content::Pagebreak { weak })
}
}
diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs
index 3468af5e..8a96e378 100644
--- a/src/library/layout/spacing.rs
+++ b/src/library/layout/spacing.rs
@@ -1,4 +1,7 @@
+use std::cmp::Ordering;
+
use crate::library::prelude::*;
+use crate::library::text::ParNode;
/// Horizontal spacing.
pub struct HNode;
@@ -6,7 +9,9 @@ pub struct HNode;
#[node]
impl HNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
- Ok(Content::Horizontal(args.expect("spacing")?))
+ let amount = args.expect("spacing")?;
+ let weak = args.named("weak")?.unwrap_or(false);
+ Ok(Content::Horizontal { amount, weak })
}
}
@@ -16,7 +21,9 @@ pub struct VNode;
#[node]
impl VNode {
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
- Ok(Content::Vertical(args.expect("spacing")?))
+ let amount = args.expect("spacing")?;
+ let weak = args.named("weak")?.unwrap_or(false);
+ Ok(Content::Vertical { amount, weak, generated: false })
}
}
@@ -25,7 +32,8 @@ impl VNode {
pub enum Spacing {
/// Spacing specified in absolute terms and relative to the parent's size.
Relative(Relative<RawLength>),
- /// Spacing specified as a fraction of the remaining free space in the parent.
+ /// Spacing specified as a fraction of the remaining free space in the
+ /// parent.
Fractional(Fraction),
}
@@ -42,6 +50,16 @@ impl From<Length> for Spacing {
}
}
+impl PartialOrd for Spacing {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ match (self, other) {
+ (Self::Relative(a), Self::Relative(b)) => a.partial_cmp(b),
+ (Self::Fractional(a), Self::Fractional(b)) => a.partial_cmp(b),
+ _ => None,
+ }
+ }
+}
+
castable! {
Spacing,
Expected: "relative length or fraction",
@@ -50,3 +68,24 @@ castable! {
Value::Relative(v) => Self::Relative(v),
Value::Fraction(v) => Self::Fractional(v),
}
+
+/// Spacing around and between block-level nodes, relative to paragraph spacing.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct BlockSpacing(Relative<RawLength>);
+
+castable!(BlockSpacing: Relative<RawLength>);
+
+impl Resolve for BlockSpacing {
+ type Output = Length;
+
+ fn resolve(self, styles: StyleChain) -> Self::Output {
+ let whole = styles.get(ParNode::SPACING);
+ self.0.resolve(styles).relative_to(whole)
+ }
+}
+
+impl From<Ratio> for BlockSpacing {
+ fn from(ratio: Ratio) -> Self {
+ Self(ratio.into())
+ }
+}
diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs
index f915c215..bbfeeab0 100644
--- a/src/library/layout/stack.rs
+++ b/src/library/layout/stack.rs
@@ -1,5 +1,6 @@
use super::{AlignNode, Spacing};
use crate::library::prelude::*;
+use crate::library::text::ParNode;
/// Arrange nodes and spacing along an axis.
#[derive(Debug, Hash)]
@@ -180,7 +181,16 @@ impl<'a> StackLayouter<'a> {
.downcast::<AlignNode>()
.and_then(|node| node.aligns.get(self.axis))
.map(|align| align.resolve(styles))
- .unwrap_or(self.dir.start().into());
+ .unwrap_or_else(|| {
+ if let Some(Content::Styled(styled)) = node.downcast::<Content>() {
+ let map = &styled.1;
+ if map.contains(ParNode::ALIGN) {
+ return StyleChain::with_root(&styled.1).get(ParNode::ALIGN);
+ }
+ }
+
+ self.dir.start().into()
+ });
let frames = node.layout(ctx, &self.regions, styles)?;
let len = frames.len();