Revise block node contract
Frames produced by block nodes are now always treated as exactly one per given region and a frame must not be larger than its respective region. Any overflow must be handled internally. This means that stack and grid don't need to search for fitting regions anymore, since the child has already does that for them. This commit further moves stack spacing into a new `SpacingNode`.
This commit is contained in:
parent
1e74f7c407
commit
6690bc2354
@ -6,7 +6,7 @@ use std::rc::Rc;
|
||||
|
||||
use super::Str;
|
||||
use crate::diag::StrResult;
|
||||
use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size};
|
||||
use crate::geom::{Align, Dir, GenAxis, Length, Linear, Sides, Size, SpecAxis};
|
||||
use crate::layout::{
|
||||
Decoration, LayoutNode, LayoutTree, PadNode, PageRun, ParChild, ParNode, StackChild,
|
||||
StackNode,
|
||||
@ -309,7 +309,7 @@ impl Builder {
|
||||
fn parbreak(&mut self) {
|
||||
let amount = self.style.par_spacing();
|
||||
self.stack.finish_par(&self.style);
|
||||
self.stack.push_soft(StackChild::Spacing(amount.into()));
|
||||
self.stack.push_soft(StackChild::spacing(amount, SpecAxis::Vertical));
|
||||
}
|
||||
|
||||
/// Apply a forced page break.
|
||||
@ -335,7 +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();
|
||||
self.stack.push(StackChild::Any(node.into(), self.style.aligns.block));
|
||||
self.stack.push(StackChild::new(node, self.style.aligns.block));
|
||||
self.parbreak();
|
||||
}
|
||||
|
||||
@ -344,7 +344,7 @@ impl Builder {
|
||||
match axis {
|
||||
GenAxis::Block => {
|
||||
self.stack.finish_par(&self.style);
|
||||
self.stack.push_hard(StackChild::Spacing(amount));
|
||||
self.stack.push_hard(StackChild::spacing(amount, SpecAxis::Vertical));
|
||||
}
|
||||
GenAxis::Inline => {
|
||||
self.stack.par.push_hard(ParChild::Spacing(amount));
|
||||
@ -508,10 +508,8 @@ impl ParBuilder {
|
||||
|
||||
fn build(self) -> Option<StackChild> {
|
||||
let Self { align, dir, line_spacing, children, .. } = self;
|
||||
(!children.is_empty()).then(|| {
|
||||
let node = ParNode { dir, line_spacing, children };
|
||||
StackChild::Any(node.into(), align)
|
||||
})
|
||||
(!children.is_empty())
|
||||
.then(|| StackChild::new(ParNode { dir, line_spacing, children }, align))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
||||
|
||||
use super::{Eval, EvalContext, Str, Template, Value};
|
||||
use crate::diag::TypResult;
|
||||
use crate::geom::Align;
|
||||
use crate::geom::{Align, SpecAxis};
|
||||
use crate::layout::{ParChild, ParNode, StackChild, StackNode};
|
||||
use crate::syntax::*;
|
||||
use crate::util::BoolExt;
|
||||
@ -119,9 +119,9 @@ fn walk_item(ctx: &mut EvalContext, label: Str, body: Template) {
|
||||
StackNode {
|
||||
dir: style.dir,
|
||||
children: vec![
|
||||
StackChild::Any(label.into(), Align::Start),
|
||||
StackChild::Spacing((style.text.size / 2.0).into()),
|
||||
StackChild::Any(body.to_stack(&style).into(), Align::Start),
|
||||
StackChild::new(label, Align::Start),
|
||||
StackChild::spacing(style.text.size / 2.0, SpecAxis::Horizontal),
|
||||
StackChild::new(body.to_stack(&style), Align::Start),
|
||||
],
|
||||
}
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ impl<T: Debug> Debug for Gen<T> {
|
||||
}
|
||||
|
||||
/// The two generic layouting axes.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum GenAxis {
|
||||
/// The axis words and lines are set along.
|
||||
Inline,
|
||||
|
@ -76,7 +76,7 @@ impl<T> Get<Side> for Sides<T> {
|
||||
}
|
||||
|
||||
/// The four sides of objects.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Side {
|
||||
/// The left side.
|
||||
Left,
|
||||
|
@ -101,7 +101,7 @@ impl<T: Debug> Debug for Spec<T> {
|
||||
}
|
||||
|
||||
/// The two specific layouting axes.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum SpecAxis {
|
||||
/// The horizontal layouting axis.
|
||||
Horizontal,
|
||||
|
@ -330,18 +330,10 @@ impl<'a> GridLayouter<'a> {
|
||||
|
||||
/// Layout the grid row-by-row.
|
||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||
let base = self.regions.base.get(self.block);
|
||||
|
||||
for y in 0 .. self.rows.len() {
|
||||
match self.rows[y] {
|
||||
TrackSizing::Auto => {
|
||||
self.layout_auto_row(ctx, y);
|
||||
}
|
||||
TrackSizing::Linear(v) => {
|
||||
let resolved = v.resolve(base);
|
||||
let frame = self.layout_single_row(ctx, resolved, y);
|
||||
self.push_row(ctx, frame);
|
||||
}
|
||||
TrackSizing::Auto => self.layout_auto_row(ctx, y),
|
||||
TrackSizing::Linear(v) => self.layout_linear_row(ctx, v, y),
|
||||
TrackSizing::Fractional(v) => {
|
||||
self.fr += v;
|
||||
self.constraints.exact.set(self.block, Some(self.full));
|
||||
@ -395,7 +387,7 @@ impl<'a> GridLayouter<'a> {
|
||||
// Layout into a single region.
|
||||
if let &[first] = resolved.as_slice() {
|
||||
let frame = self.layout_single_row(ctx, first, y);
|
||||
self.push_row(ctx, frame);
|
||||
self.push_row(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -414,14 +406,39 @@ impl<'a> GridLayouter<'a> {
|
||||
let frames = self.layout_multi_row(ctx, &resolved, y);
|
||||
let len = frames.len();
|
||||
for (i, frame) in frames.into_iter().enumerate() {
|
||||
self.push_row(frame);
|
||||
if i + 1 < len {
|
||||
self.constraints.exact.set(self.block, Some(self.full));
|
||||
self.finish_region(ctx);
|
||||
}
|
||||
self.push_row(ctx, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/// Layout a row with a fixed size along the block axis.
|
||||
/// Layout a row with linear sizing along the block axis. Such a row cannot
|
||||
/// break across multiple regions, but it may force a region break.
|
||||
fn layout_linear_row(&mut self, ctx: &mut LayoutContext, v: Linear, y: usize) {
|
||||
let base = self.regions.base.get(self.block);
|
||||
let resolved = v.resolve(base);
|
||||
let frame = self.layout_single_row(ctx, resolved, y);
|
||||
|
||||
// Skip to fitting region.
|
||||
let length = frame.size.get(self.block);
|
||||
while !self.regions.current.get(self.block).fits(length)
|
||||
&& !self.regions.in_full_last()
|
||||
{
|
||||
self.constraints.max.set(self.block, Some(self.used.block + length));
|
||||
self.finish_region(ctx);
|
||||
|
||||
// Don't skip multiple regions for gutter and don't push a row.
|
||||
if y % 2 == 1 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
self.push_row(frame);
|
||||
}
|
||||
|
||||
/// Layout a row with a fixed size along the block axis and return its frame.
|
||||
fn layout_single_row(
|
||||
&self,
|
||||
ctx: &mut LayoutContext,
|
||||
@ -508,19 +525,9 @@ impl<'a> GridLayouter<'a> {
|
||||
outputs
|
||||
}
|
||||
|
||||
/// Push a row frame into the current or next fitting region, finishing
|
||||
/// regions (including layouting fractional rows) if necessary.
|
||||
fn push_row(&mut self, ctx: &mut LayoutContext, frame: Frame) {
|
||||
/// Push a row frame into the current region.
|
||||
fn push_row(&mut self, frame: Frame) {
|
||||
let length = frame.size.get(self.block);
|
||||
|
||||
// Skip to fitting region.
|
||||
while !self.regions.current.get(self.block).fits(length)
|
||||
&& !self.regions.in_full_last()
|
||||
{
|
||||
self.constraints.max.set(self.block, Some(self.used.block + length));
|
||||
self.finish_region(ctx);
|
||||
}
|
||||
|
||||
*self.regions.current.get_mut(self.block) -= length;
|
||||
self.used.block += length;
|
||||
self.lrows.push(Row::Frame(frame));
|
||||
|
@ -23,18 +23,18 @@ impl Layout for ImageNode {
|
||||
let pixel_size = Spec::new(img.width() as f64, img.height() as f64);
|
||||
let pixel_ratio = pixel_size.x / pixel_size.y;
|
||||
|
||||
let mut constraints = Constraints::new(regions.expand);
|
||||
constraints.set_base_if_linear(regions.base, Spec::new(self.width, self.height));
|
||||
|
||||
let width = self.width.map(|w| w.resolve(regions.base.w));
|
||||
let height = self.height.map(|w| w.resolve(regions.base.h));
|
||||
|
||||
let mut cts = Constraints::new(regions.expand);
|
||||
cts.set_base_if_linear(regions.base, Spec::new(self.width, self.height));
|
||||
|
||||
let size = match (width, height) {
|
||||
(Some(width), Some(height)) => Size::new(width, height),
|
||||
(Some(width), None) => Size::new(width, width / pixel_ratio),
|
||||
(None, Some(height)) => Size::new(height * pixel_ratio, height),
|
||||
(None, None) => {
|
||||
constraints.exact.x = Some(regions.current.w);
|
||||
cts.exact.x = Some(regions.current.w);
|
||||
if regions.current.w.is_finite() {
|
||||
// Fit to width.
|
||||
Size::new(regions.current.w, regions.current.w / pixel_ratio)
|
||||
@ -48,7 +48,7 @@ impl Layout for ImageNode {
|
||||
|
||||
let mut frame = Frame::new(size, size.h);
|
||||
frame.push(Point::zero(), Element::Image(self.id, size));
|
||||
vec![frame.constrain(constraints)]
|
||||
vec![frame.constrain(cts)]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ mod par;
|
||||
mod regions;
|
||||
mod shape;
|
||||
mod shaping;
|
||||
mod spacing;
|
||||
mod stack;
|
||||
mod tree;
|
||||
|
||||
@ -25,6 +26,7 @@ pub use par::*;
|
||||
pub use regions::*;
|
||||
pub use shape::*;
|
||||
pub use shaping::*;
|
||||
pub use spacing::*;
|
||||
pub use stack::*;
|
||||
pub use tree::*;
|
||||
|
||||
|
@ -46,7 +46,8 @@ impl Layout for ShapeNode {
|
||||
let mut cts = Constraints::new(regions.expand);
|
||||
cts.set_base_if_linear(regions.base, Spec::new(self.width, self.height));
|
||||
|
||||
// Set exact and base constraint if child is automatically sized.
|
||||
// Set tight exact and base constraints if the child is
|
||||
// automatically sized since we don't know what the child might do.
|
||||
if self.width.is_none() {
|
||||
cts.exact.x = Some(regions.current.w);
|
||||
cts.base.x = Some(regions.base.w);
|
||||
|
@ -48,6 +48,7 @@ pub fn shape<'a>(
|
||||
/// This type contains owned or borrowed shaped text runs, which can be
|
||||
/// measured, used to reshape substrings more quickly and converted into a
|
||||
/// frame.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShapedText<'a> {
|
||||
/// The text that was shaped.
|
||||
pub text: &'a str,
|
||||
@ -64,7 +65,7 @@ pub struct ShapedText<'a> {
|
||||
}
|
||||
|
||||
/// A single glyph resulting from shaping.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ShapedGlyph {
|
||||
/// The font face the glyph is contained in.
|
||||
pub face_id: FaceId,
|
||||
|
50
src/layout/spacing.rs
Normal file
50
src/layout/spacing.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use super::*;
|
||||
|
||||
/// Spacing between other nodes.
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct SpacingNode {
|
||||
/// Which axis to space on.
|
||||
pub axis: SpecAxis,
|
||||
/// How much spacing to add.
|
||||
pub amount: Linear,
|
||||
}
|
||||
|
||||
impl Layout for SpacingNode {
|
||||
fn layout(
|
||||
&self,
|
||||
_: &mut LayoutContext,
|
||||
regions: &Regions,
|
||||
) -> Vec<Constrained<Rc<Frame>>> {
|
||||
let base = regions.base.get(self.axis);
|
||||
let resolved = self.amount.resolve(base);
|
||||
let limit = regions.current.get(self.axis);
|
||||
|
||||
// Generate constraints.
|
||||
let mut cts = Constraints::new(regions.expand);
|
||||
if self.amount.is_relative() {
|
||||
cts.base.set(self.axis, Some(base));
|
||||
}
|
||||
|
||||
// If the spacing fits into the region, any larger region would also do.
|
||||
// If it was limited though, any change it region size might lead to
|
||||
// different results.
|
||||
if resolved < limit {
|
||||
cts.min.set(self.axis, Some(resolved));
|
||||
} else {
|
||||
cts.exact.set(self.axis, Some(limit));
|
||||
}
|
||||
|
||||
// Create frame with limited spacing size along spacing axis and zero
|
||||
// extent along the other axis.
|
||||
let mut size = Size::zero();
|
||||
size.set(self.axis, resolved.min(limit));
|
||||
vec![Frame::new(size, size.h).constrain(cts)]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpacingNode> for LayoutNode {
|
||||
fn from(spacing: SpacingNode) -> Self {
|
||||
Self::new(spacing)
|
||||
}
|
||||
}
|
@ -12,15 +12,6 @@ pub struct StackNode {
|
||||
pub children: Vec<StackChild>,
|
||||
}
|
||||
|
||||
/// A child of a stack node.
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub enum StackChild {
|
||||
/// Spacing between other nodes.
|
||||
Spacing(Linear),
|
||||
/// Any child node and how to align it in the stack.
|
||||
Any(LayoutNode, Align),
|
||||
}
|
||||
|
||||
impl Layout for StackNode {
|
||||
fn layout(
|
||||
&self,
|
||||
@ -37,12 +28,31 @@ impl From<StackNode> for LayoutNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A child of a stack node.
|
||||
#[cfg_attr(feature = "layout-cache", derive(Hash))]
|
||||
pub struct StackChild {
|
||||
/// The node itself.
|
||||
pub node: LayoutNode,
|
||||
/// How to align the node along the block axis.
|
||||
pub align: Align,
|
||||
}
|
||||
|
||||
impl StackChild {
|
||||
/// Create a new stack child.
|
||||
pub fn new(node: impl Into<LayoutNode>, align: Align) -> Self {
|
||||
Self { node: node.into(), align }
|
||||
}
|
||||
|
||||
/// Create a spacing stack child.
|
||||
pub fn spacing(amount: impl Into<Linear>, axis: SpecAxis) -> Self {
|
||||
Self::new(SpacingNode { amount: amount.into(), axis }, Align::Start)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for StackChild {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Spacing(v) => write!(f, "Spacing({:?})", v),
|
||||
Self::Any(node, _) => node.fmt(f),
|
||||
}
|
||||
write!(f, "{:?}: ", self.align)?;
|
||||
self.node.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +61,7 @@ struct StackLayouter<'a> {
|
||||
/// The stack node to layout.
|
||||
stack: &'a StackNode,
|
||||
/// The axis of the block direction.
|
||||
block: SpecAxis,
|
||||
axis: SpecAxis,
|
||||
/// Whether the stack should expand to fill the region.
|
||||
expand: Spec<bool>,
|
||||
/// The region to layout into.
|
||||
@ -63,10 +73,6 @@ struct StackLayouter<'a> {
|
||||
used: Gen<Length>,
|
||||
/// The alignment ruler for the current region.
|
||||
ruler: Align,
|
||||
/// The constraints for the current region.
|
||||
constraints: Constraints,
|
||||
/// Whether the last region can fit all the remaining content.
|
||||
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, Align, Rc<Frame>)>,
|
||||
@ -77,23 +83,21 @@ struct StackLayouter<'a> {
|
||||
impl<'a> StackLayouter<'a> {
|
||||
/// Create a new stack layouter.
|
||||
fn new(stack: &'a StackNode, mut regions: Regions) -> Self {
|
||||
let block = stack.dir.axis();
|
||||
let axis = stack.dir.axis();
|
||||
let full = regions.current;
|
||||
let expand = regions.expand;
|
||||
|
||||
// Disable expansion along the block axis for children.
|
||||
regions.expand.set(block, false);
|
||||
regions.expand.set(axis, false);
|
||||
|
||||
Self {
|
||||
stack,
|
||||
block,
|
||||
axis,
|
||||
expand,
|
||||
regions,
|
||||
full,
|
||||
used: Gen::zero(),
|
||||
ruler: Align::Start,
|
||||
constraints: Constraints::new(expand),
|
||||
overflowing: false,
|
||||
frames: vec![],
|
||||
finished: vec![],
|
||||
}
|
||||
@ -102,17 +106,12 @@ impl<'a> StackLayouter<'a> {
|
||||
/// Layout all children.
|
||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||
for child in &self.stack.children {
|
||||
match *child {
|
||||
StackChild::Spacing(amount) => self.space(amount),
|
||||
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, align);
|
||||
}
|
||||
let frames = child.node.layout(ctx, &self.regions);
|
||||
let len = frames.len();
|
||||
for (i, frame) in frames.into_iter().enumerate() {
|
||||
self.push_frame(frame.item, child.align);
|
||||
if i + 1 < len {
|
||||
self.finish_region();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,96 +120,37 @@ impl<'a> StackLayouter<'a> {
|
||||
self.finished
|
||||
}
|
||||
|
||||
/// Add block-axis spacing into the current region.
|
||||
fn space(&mut self, amount: Linear) {
|
||||
// Resolve the linear.
|
||||
let full = self.full.get(self.block);
|
||||
let resolved = amount.resolve(full);
|
||||
|
||||
// Cap the spacing to the remaining available space. This action does
|
||||
// not directly affect the constraints because of the cap.
|
||||
let remaining = self.regions.current.get_mut(self.block);
|
||||
let capped = resolved.min(*remaining);
|
||||
|
||||
// Grow our size and shrink the available space in the region.
|
||||
self.used.block += capped;
|
||||
*remaining -= capped;
|
||||
}
|
||||
|
||||
/// Push a frame into the current or next fitting region, finishing regions
|
||||
/// if necessary.
|
||||
/// Push a frame into the current region.
|
||||
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 align < self.ruler {
|
||||
self.finish_region();
|
||||
}
|
||||
|
||||
// Find a fitting region.
|
||||
while !self.regions.current.get(self.block).fits(size.block) {
|
||||
if self.regions.in_full_last() {
|
||||
self.overflowing = true;
|
||||
break;
|
||||
}
|
||||
|
||||
self.constraints
|
||||
.max
|
||||
.get_mut(self.block)
|
||||
.set_min(self.used.block + size.block);
|
||||
|
||||
self.finish_region();
|
||||
}
|
||||
|
||||
// Shrink available space in the region.
|
||||
*self.regions.current.get_mut(self.block) -= size.block;
|
||||
|
||||
// Grow our size.
|
||||
let offset = self.used.block;
|
||||
let size = frame.size.to_gen(self.axis);
|
||||
self.used.block += size.block;
|
||||
self.used.inline.set_max(size.inline);
|
||||
self.ruler = align;
|
||||
self.ruler = self.ruler.max(align);
|
||||
|
||||
// Remember the frame with offset and alignment.
|
||||
self.frames.push((offset, align, frame));
|
||||
// Remember the frame and shrink available space in the region for the
|
||||
// following children.
|
||||
self.frames.push((offset, self.ruler, frame));
|
||||
*self.regions.current.get_mut(self.axis) -= size.block;
|
||||
}
|
||||
|
||||
/// Finish the frame for one region.
|
||||
fn finish_region(&mut self) {
|
||||
let expand = self.expand;
|
||||
let used = self.used.to_size(self.block);
|
||||
|
||||
// Determine the stack's size dependening on whether the region expands.
|
||||
let used = self.used.to_size(self.axis);
|
||||
let size = Size::new(
|
||||
if expand.x {
|
||||
self.constraints.exact.x = Some(self.full.w);
|
||||
self.full.w
|
||||
} else {
|
||||
self.constraints.min.x = Some(used.w.min(self.full.w));
|
||||
used.w
|
||||
},
|
||||
if expand.y {
|
||||
self.constraints.exact.y = Some(self.full.h);
|
||||
self.full.h
|
||||
} else {
|
||||
self.constraints.min.y = Some(used.h.min(self.full.h));
|
||||
used.h
|
||||
},
|
||||
if self.expand.x { self.full.w } else { used.w },
|
||||
if self.expand.y { self.full.h } else { used.h },
|
||||
);
|
||||
|
||||
if self.overflowing {
|
||||
self.constraints.min.y = None;
|
||||
self.constraints.max.y = None;
|
||||
self.constraints.exact = self.full.to_spec().map(Some);
|
||||
}
|
||||
|
||||
let mut output = Frame::new(size, size.h);
|
||||
let mut first = true;
|
||||
|
||||
// Place all frames.
|
||||
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);
|
||||
let stack_size = size.to_gen(self.axis);
|
||||
let child_size = frame.size.to_gen(self.axis);
|
||||
|
||||
// Align along the block axis.
|
||||
let block = align.resolve(
|
||||
@ -224,7 +164,7 @@ impl<'a> StackLayouter<'a> {
|
||||
},
|
||||
);
|
||||
|
||||
let pos = Gen::new(Length::zero(), block).to_point(self.block);
|
||||
let pos = Gen::new(Length::zero(), block).to_point(self.axis);
|
||||
|
||||
// The baseline of the stack is that of the first frame.
|
||||
if first {
|
||||
@ -235,11 +175,15 @@ impl<'a> StackLayouter<'a> {
|
||||
output.push_frame(pos, frame);
|
||||
}
|
||||
|
||||
// Generate tight constraints for now.
|
||||
let mut cts = Constraints::new(self.expand);
|
||||
cts.exact = self.full.to_spec().map(Some);
|
||||
cts.base = self.regions.base.to_spec().map(Some);
|
||||
|
||||
self.regions.next();
|
||||
self.full = self.regions.current;
|
||||
self.used = Gen::zero();
|
||||
self.ruler = Align::Start;
|
||||
self.finished.push(output.constrain(self.constraints));
|
||||
self.constraints = Constraints::new(expand);
|
||||
self.finished.push(output.constrain(cts));
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ impl Layout for LayoutNode {
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
if !entry.check(regions) {
|
||||
eprintln!("node: {:#?}", self.node);
|
||||
eprintln!("regions: {:#?}", regions);
|
||||
eprintln!(
|
||||
"constraints: {:#?}",
|
||||
|
@ -209,7 +209,7 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
}
|
||||
|
||||
let dir = args.named("dir")?.unwrap_or(Dir::TTB);
|
||||
let spacing = args.named("spacing")?;
|
||||
let spacing = args.named::<Linear>("spacing")?;
|
||||
let list: Vec<Child> = args.all().collect();
|
||||
|
||||
Ok(Value::Template(Template::from_block(move |style| {
|
||||
@ -220,16 +220,16 @@ pub fn stack(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||
for child in &list {
|
||||
match child {
|
||||
Child::Spacing(v) => {
|
||||
children.push(StackChild::Spacing(*v));
|
||||
children.push(StackChild::spacing(*v, dir.axis()));
|
||||
delayed = None;
|
||||
}
|
||||
Child::Any(template) => {
|
||||
if let Some(v) = delayed {
|
||||
children.push(StackChild::Spacing(v));
|
||||
children.push(StackChild::spacing(v, dir.axis()));
|
||||
}
|
||||
|
||||
let node = template.to_stack(style).into();
|
||||
children.push(StackChild::Any(node, style.aligns.block));
|
||||
let node = template.to_stack(style);
|
||||
children.push(StackChild::new(node, style.aligns.block));
|
||||
delayed = spacing;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Loading…
x
Reference in New Issue
Block a user