Remove inline alignment from stack

The current inline alignment is very broken and leads to lots of subtle weirdness. Getting rid of it simplifies the stack's interface a lot. At a later point either:
- inline alignment will be added back in a better way, or
- all nodes will be able to expand or align themselves, meaning that the stack's children take care of their alignment
This commit is contained in:
Laurenz 2021-10-13 14:15:17 +02:00
parent 9ac125dea8
commit 5f4dde0a6b
6 changed files with 33 additions and 62 deletions

View File

@ -6,7 +6,7 @@ use std::rc::Rc;
use super::Str;
use crate::diag::StrResult;
use crate::geom::{Align, Dir, Gen, GenAxis, Length, Linear, Sides, Size};
use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size};
use crate::layout::{
Decoration, LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild,
StackNode,
@ -335,8 +335,7 @@ impl Builder {
/// Push a block node into the active stack, finishing the active paragraph.
fn block(&mut self, node: impl Into<LayoutNode>) {
self.parbreak();
let aligns = self.style.aligns;
self.stack.push(StackChild::Any(node.into(), aligns));
self.stack.push(StackChild::Any(node.into(), self.style.aligns.block));
self.parbreak();
}
@ -407,7 +406,7 @@ impl PageBuilder {
}
struct StackBuilder {
dirs: Gen<Dir>,
dir: Dir,
children: Vec<StackChild>,
last: Last<StackChild>,
par: ParBuilder,
@ -416,7 +415,7 @@ struct StackBuilder {
impl StackBuilder {
fn new(style: &Style) -> Self {
Self {
dirs: Gen::new(style.dir, Dir::TTB),
dir: Dir::TTB,
children: vec![],
last: Last::None,
par: ParBuilder::new(style),
@ -445,17 +444,17 @@ impl StackBuilder {
}
fn build(self) -> StackNode {
let Self { dirs, mut children, par, mut last } = self;
let Self { dir, mut children, par, mut last } = self;
if let Some(par) = par.build() {
children.extend(last.any());
children.push(par);
}
StackNode { dirs, children }
StackNode { dir, children }
}
}
struct ParBuilder {
aligns: Gen<Align>,
align: Align,
dir: Dir,
line_spacing: Length,
children: Vec<ParChild>,
@ -465,7 +464,7 @@ struct ParBuilder {
impl ParBuilder {
fn new(style: &Style) -> Self {
Self {
aligns: style.aligns,
align: style.aligns.block,
dir: style.dir,
line_spacing: style.line_spacing(),
children: vec![],
@ -508,10 +507,10 @@ impl ParBuilder {
}
fn build(self) -> Option<StackChild> {
let Self { aligns, dir, line_spacing, children, .. } = self;
let Self { align, dir, line_spacing, children, .. } = self;
(!children.is_empty()).then(|| {
let node = ParNode { dir, line_spacing, children };
StackChild::Any(node.into(), aligns)
StackChild::Any(node.into(), align)
})
}
}

View File

@ -2,7 +2,7 @@ use std::rc::Rc;
use super::{Eval, EvalContext, Str, Template, Value};
use crate::diag::TypResult;
use crate::geom::{Dir, Gen};
use crate::geom::Align;
use crate::layout::{ParChild, ParNode, StackChild, StackNode};
use crate::syntax::*;
use crate::util::BoolExt;
@ -117,11 +117,11 @@ fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) {
)],
};
StackNode {
dirs: Gen::new(Dir::TTB, style.dir),
dir: style.dir,
children: vec![
StackChild::Any(label.into(), Gen::default()),
StackChild::Any(label.into(), Align::Start),
StackChild::Spacing((style.text.size / 2.0).into()),
StackChild::Any(body.to_stack(&style).into(), Gen::default()),
StackChild::Any(body.to_stack(&style).into(), Align::Start),
],
}
});

View File

@ -6,11 +6,8 @@ use super::*;
#[derive(Debug)]
#[cfg_attr(feature = "layout-cache", derive(Hash))]
pub struct StackNode {
/// The inline and block directions of this stack.
///
/// The children are stacked along the block direction. The inline direction
/// is required for aligning the children.
pub dirs: Gen<Dir>,
/// The stacking direction.
pub dir: Dir,
/// The nodes to be stacked.
pub children: Vec<StackChild>,
}
@ -21,7 +18,7 @@ pub enum StackChild {
/// Spacing between other nodes.
Spacing(Linear),
/// Any child node and how to align it in the stack.
Any(LayoutNode, Gen<Align>),
Any(LayoutNode, Align),
}
impl Layout for StackNode {
@ -72,7 +69,7 @@ struct StackLayouter<'a> {
overflowing: bool,
/// Offset, alignment and frame for all children that fit into the current
/// region. The exact positions are not known yet.
frames: Vec<(Length, Gen<Align>, Rc<Frame>)>,
frames: Vec<(Length, Align, Rc<Frame>)>,
/// Finished frames for previous regions.
finished: Vec<Constrained<Rc<Frame>>>,
}
@ -80,7 +77,7 @@ struct StackLayouter<'a> {
impl<'a> StackLayouter<'a> {
/// Create a new stack layouter.
fn new(stack: &'a StackNode, mut regions: Regions) -> Self {
let block = stack.dirs.block.axis();
let block = stack.dir.axis();
let full = regions.current;
let expand = regions.expand;
@ -107,14 +104,14 @@ impl<'a> StackLayouter<'a> {
for child in &self.stack.children {
match *child {
StackChild::Spacing(amount) => self.space(amount),
StackChild::Any(ref node, aligns) => {
StackChild::Any(ref node, align) => {
let nodes = node.layout(ctx, &self.regions);
let len = nodes.len();
for (i, frame) in nodes.into_iter().enumerate() {
if i + 1 < len {
self.constraints.exact = self.full.to_spec().map(Some);
}
self.push_frame(frame.item, aligns);
self.push_frame(frame.item, align);
}
}
}
@ -142,11 +139,11 @@ impl<'a> StackLayouter<'a> {
/// Push a frame into the current or next fitting region, finishing regions
/// if necessary.
fn push_frame(&mut self, frame: Rc<Frame>, aligns: Gen<Align>) {
fn push_frame(&mut self, frame: Rc<Frame>, align: Align) {
let size = frame.size.to_gen(self.block);
// Don't allow `Start` after `End` in the same region.
if aligns.block < self.ruler {
if align < self.ruler {
self.finish_region();
}
@ -172,10 +169,10 @@ impl<'a> StackLayouter<'a> {
let offset = self.used.block;
self.used.block += size.block;
self.used.inline.set_max(size.inline);
self.ruler = aligns.block;
self.ruler = align;
// Remember the frame with offset and alignment.
self.frames.push((offset, aligns, frame));
self.frames.push((offset, align, frame));
}
/// Finish the frame for one region.
@ -211,20 +208,14 @@ impl<'a> StackLayouter<'a> {
let mut first = true;
// Place all frames.
for (offset, aligns, frame) in self.frames.drain(..) {
for (offset, align, frame) in self.frames.drain(..) {
let stack_size = size.to_gen(self.block);
let child_size = frame.size.to_gen(self.block);
// Align along the inline axis.
let inline = aligns.inline.resolve(
self.stack.dirs.inline,
Length::zero() .. stack_size.inline - child_size.inline,
);
// Align along the block axis.
let block = aligns.block.resolve(
self.stack.dirs.block,
if self.stack.dirs.block.is_positive() {
let block = align.resolve(
self.stack.dir,
if self.stack.dir.is_positive() {
offset .. stack_size.block - self.used.block + offset
} else {
let offset_with_self = offset + child_size.block;
@ -233,7 +224,7 @@ impl<'a> StackLayouter<'a> {
},
);
let pos = Gen::new(inline, block).to_point(self.block);
let pos = Gen::new(Length::zero(), block).to_point(self.block);
// The baseline of the stack is that of the first frame.
if first {

View File

@ -204,27 +204,11 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
Value::Template(v) => Self::Any(v),
}
let dir = args.named("dir")?;
let dir = args.named("dir")?.unwrap_or(Dir::TTB);
let spacing = args.named("spacing")?;
let list: Vec<Child> = args.all().collect();
Ok(Value::Template(Template::from_block(move |style| {
let mut dirs = Gen::new(style.dir, dir.unwrap_or(Dir::TTB));
// If the directions become aligned, fix up the inline direction since
// that's the one that is not user-defined.
if dirs.inline.axis() == dirs.block.axis() {
dirs.inline = Dir::TTB;
}
// Use the current alignments for all children, but take care to apply
// them to the correct axes (by swapping them if the stack axes are
// different from the style axes).
let mut aligns = style.aligns;
if dirs.inline.axis() != style.dir.axis() {
aligns = Gen::new(aligns.block, aligns.inline);
}
let mut children = vec![];
let mut delayed = None;
@ -241,13 +225,13 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
}
let node = template.to_stack(style).into();
children.push(StackChild::Any(node, aligns));
children.push(StackChild::Any(node, style.aligns.block));
delayed = spacing;
}
}
}
StackNode { dirs, children }
StackNode { dir, children }
})))
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 B

After

Width:  |  Height:  |  Size: 319 B

View File

@ -20,9 +20,6 @@
#stack(dir: btt, ..items)
#pagebreak()
// Currently stack works like flexbox apparently.
#stack(dir: ltr, ..items)
---
// Test spacing.
#page(width: 50pt, margins: 0pt)