mirror of
https://github.com/typst/typst
synced 2025-06-28 08:12:53 +08:00
Layout bugfixes
This commit is contained in:
parent
50bd863471
commit
e36b8ed374
@ -85,6 +85,27 @@ impl<T> Spec<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Spec<T>
|
||||||
|
where
|
||||||
|
T: Ord,
|
||||||
|
{
|
||||||
|
/// The component-wise minimum of this and another instance.
|
||||||
|
pub fn min(self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x.min(other.x),
|
||||||
|
y: self.y.min(other.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The component-wise minimum of this and another instance.
|
||||||
|
pub fn max(self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
x: self.x.max(other.x),
|
||||||
|
y: self.y.max(other.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Get<SpecAxis> for Spec<T> {
|
impl<T> Get<SpecAxis> for Spec<T> {
|
||||||
type Component = T;
|
type Component = T;
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ impl Layout for AlignNode {
|
|||||||
// Set constraints.
|
// Set constraints.
|
||||||
cts.expand = regions.expand;
|
cts.expand = regions.expand;
|
||||||
cts.base = base.filter(cts.base.map_is_some());
|
cts.base = base.filter(cts.base.map_is_some());
|
||||||
cts.exact = current.filter(regions.expand);
|
cts.exact = current.filter(regions.expand | cts.exact.map_is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
frames
|
frames
|
||||||
|
@ -132,10 +132,6 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
/// Layout all children.
|
/// Layout all children.
|
||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
for child in self.children {
|
for child in self.children {
|
||||||
if self.regions.is_full() {
|
|
||||||
self.finish_region();
|
|
||||||
}
|
|
||||||
|
|
||||||
match *child {
|
match *child {
|
||||||
FlowChild::Spacing(Spacing::Linear(v)) => {
|
FlowChild::Spacing(Spacing::Linear(v)) => {
|
||||||
self.layout_absolute(v);
|
self.layout_absolute(v);
|
||||||
@ -145,6 +141,10 @@ impl<'a> FlowLayouter<'a> {
|
|||||||
self.fr += v;
|
self.fr += v;
|
||||||
}
|
}
|
||||||
FlowChild::Node(ref node) => {
|
FlowChild::Node(ref node) => {
|
||||||
|
if self.regions.is_full() {
|
||||||
|
self.finish_region();
|
||||||
|
}
|
||||||
|
|
||||||
self.layout_node(ctx, node);
|
self.layout_node(ctx, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,7 @@ impl<'a> GridLayouter<'a> {
|
|||||||
size.y = self.full;
|
size.y = self.full;
|
||||||
self.cts.exact.y = Some(self.full);
|
self.cts.exact.y = Some(self.full);
|
||||||
} else {
|
} else {
|
||||||
self.cts.min.y = Some(size.y);
|
self.cts.min.y = Some(size.y.min(self.full));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frame for the region.
|
// The frame for the region.
|
||||||
@ -575,11 +575,12 @@ impl<'a> GridLayouter<'a> {
|
|||||||
pos.y += height;
|
pos.y += height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cts.base = self.regions.base.map(Some);
|
||||||
|
self.finished.push(output.constrain(self.cts));
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.full = self.regions.current.y;
|
self.full = self.regions.current.y;
|
||||||
self.used.y = Length::zero();
|
self.used.y = Length::zero();
|
||||||
self.fr = Fractional::zero();
|
self.fr = Fractional::zero();
|
||||||
self.finished.push(output.constrain(self.cts));
|
|
||||||
self.cts = Constraints::new(self.expand);
|
self.cts = Constraints::new(self.expand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,34 +40,34 @@ impl Layout for ImageNode {
|
|||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Rc<Frame>>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
let &Regions { current, expand, .. } = regions;
|
|
||||||
|
|
||||||
let img = ctx.images.get(self.id);
|
let img = ctx.images.get(self.id);
|
||||||
let pxw = img.width() as f64;
|
let pxw = img.width() as f64;
|
||||||
let pxh = img.height() as f64;
|
let pxh = img.height() as f64;
|
||||||
|
let px_ratio = pxw / pxh;
|
||||||
|
|
||||||
let pixel_ratio = pxw / pxh;
|
// Find out whether the image is wider or taller than the target size.
|
||||||
|
let current = regions.current;
|
||||||
let current_ratio = current.x / current.y;
|
let current_ratio = current.x / current.y;
|
||||||
let wide = pixel_ratio > current_ratio;
|
let wide = px_ratio > current_ratio;
|
||||||
|
|
||||||
// The space into which the image will be placed according to its fit.
|
// The space into which the image will be placed according to its fit.
|
||||||
let target = if expand.x && expand.y {
|
let target = if regions.expand.x && regions.expand.y {
|
||||||
current
|
current
|
||||||
} else if expand.x || (wide && current.x.is_finite()) {
|
} else if regions.expand.x || (wide && current.x.is_finite()) {
|
||||||
Size::new(current.x, current.y.min(current.x.safe_div(pixel_ratio)))
|
Size::new(current.x, current.y.min(current.x.safe_div(px_ratio)))
|
||||||
} else if current.y.is_finite() {
|
} else if current.y.is_finite() {
|
||||||
Size::new(current.x.min(current.y * pixel_ratio), current.y)
|
Size::new(current.x.min(current.y * px_ratio), current.y)
|
||||||
} else {
|
} else {
|
||||||
Size::new(Length::pt(pxw), Length::pt(pxh))
|
Size::new(Length::pt(pxw), Length::pt(pxh))
|
||||||
};
|
};
|
||||||
|
|
||||||
// The actual size of the fitted image.
|
// The actual size of the fitted image.
|
||||||
let size = match self.fit {
|
let fitted = match self.fit {
|
||||||
ImageFit::Contain | ImageFit::Cover => {
|
ImageFit::Contain | ImageFit::Cover => {
|
||||||
if wide == (self.fit == ImageFit::Contain) {
|
if wide == (self.fit == ImageFit::Contain) {
|
||||||
Size::new(target.x, target.x / pixel_ratio)
|
Size::new(target.x, target.x / px_ratio)
|
||||||
} else {
|
} else {
|
||||||
Size::new(target.y * pixel_ratio, target.y)
|
Size::new(target.y * px_ratio, target.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImageFit::Stretch => target,
|
ImageFit::Stretch => target,
|
||||||
@ -76,8 +76,8 @@ impl Layout for ImageNode {
|
|||||||
// First, place the image in a frame of exactly its size and then resize
|
// First, place the image in a frame of exactly its size and then resize
|
||||||
// the frame to the target size, center aligning the image in the
|
// the frame to the target size, center aligning the image in the
|
||||||
// process.
|
// process.
|
||||||
let mut frame = Frame::new(size);
|
let mut frame = Frame::new(fitted);
|
||||||
frame.push(Point::zero(), Element::Image(self.id, size));
|
frame.push(Point::zero(), Element::Image(self.id, fitted));
|
||||||
frame.resize(target, Align::CENTER_HORIZON);
|
frame.resize(target, Align::CENTER_HORIZON);
|
||||||
|
|
||||||
// Create a clipping group if the fit mode is "cover".
|
// Create a clipping group if the fit mode is "cover".
|
||||||
|
@ -231,8 +231,7 @@ impl<'a> ParLayouter<'a> {
|
|||||||
}
|
}
|
||||||
ParChild::Node(ref node) => {
|
ParChild::Node(ref node) => {
|
||||||
let size = Size::new(regions.current.x, regions.base.y);
|
let size = Size::new(regions.current.x, regions.base.y);
|
||||||
let expand = Spec::splat(false);
|
let pod = Regions::one(size, regions.base, Spec::splat(false));
|
||||||
let pod = Regions::one(size, regions.base, expand);
|
|
||||||
let frame = node.layout(ctx, &pod).remove(0);
|
let frame = node.layout(ctx, &pod).remove(0);
|
||||||
items.push(ParItem::Frame(Rc::take(frame.item)));
|
items.push(ParItem::Frame(Rc::take(frame.item)));
|
||||||
ranges.push(range);
|
ranges.push(range);
|
||||||
@ -288,27 +287,33 @@ impl<'a> ParLayouter<'a> {
|
|||||||
// line cannot be broken up further.
|
// line cannot be broken up further.
|
||||||
if !stack.regions.current.fits(line.size) {
|
if !stack.regions.current.fits(line.size) {
|
||||||
if let Some((last_line, last_end)) = last.take() {
|
if let Some((last_line, last_end)) = last.take() {
|
||||||
|
let fits =
|
||||||
|
stack.regions.current.zip(line.size).map(|(c, s)| c.fits(s));
|
||||||
|
|
||||||
// Since the new line try did not fit, no region that would
|
// Since the new line try did not fit, no region that would
|
||||||
// fit the line will yield the same line break. Therefore,
|
// fit the line will yield the same line break. Therefore,
|
||||||
// the width of the region must not fit the width of the
|
// the width of the region must not fit the width of the
|
||||||
// tried line.
|
// tried line.
|
||||||
if !stack.regions.current.x.fits(line.size.x) {
|
if !fits.x {
|
||||||
stack.cts.max.x.set_min(line.size.x);
|
stack.cts.max.x.set_min(line.size.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as above, but for height.
|
// Same as above, but for height.
|
||||||
if !stack.regions.current.y.fits(line.size.y) {
|
if !fits.y {
|
||||||
let too_large = stack.size.y + self.leading + line.size.y;
|
let too_large = stack.size.y + self.leading + line.size.y;
|
||||||
stack.cts.max.y.set_min(too_large);
|
stack.cts.max.y.set_min(too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't start new lines at every opportunity when we are
|
||||||
|
// overflowing.
|
||||||
|
if !stack.overflowing || !fits.x {
|
||||||
stack.push(last_line);
|
stack.push(last_line);
|
||||||
|
|
||||||
stack.cts.min.y = Some(stack.size.y);
|
stack.cts.min.y = Some(stack.size.y);
|
||||||
start = last_end;
|
start = last_end;
|
||||||
line = LineLayout::new(ctx, &self, start .. end);
|
line = LineLayout::new(ctx, &self, start .. end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the line does not fit vertically, we start a new region.
|
// If the line does not fit vertically, we start a new region.
|
||||||
while !stack.regions.current.y.fits(line.size.y) {
|
while !stack.regions.current.y.fits(line.size.y) {
|
||||||
@ -322,7 +327,6 @@ impl<'a> ParLayouter<'a> {
|
|||||||
// below.
|
// below.
|
||||||
let too_large = stack.size.y + self.leading + line.size.y;
|
let too_large = stack.size.y + self.leading + line.size.y;
|
||||||
stack.cts.max.y.set_min(too_large);
|
stack.cts.max.y.set_min(too_large);
|
||||||
|
|
||||||
stack.finish_region(ctx);
|
stack.finish_region(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,12 +648,12 @@ impl<'a> LineStack<'a> {
|
|||||||
output.merge_frame(pos, frame);
|
output.merge_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.cts.base = self.regions.base.map(Some);
|
||||||
self.finished.push(output.constrain(self.cts));
|
self.finished.push(output.constrain(self.cts));
|
||||||
self.regions.next();
|
self.regions.next();
|
||||||
self.full = self.regions.current;
|
self.full = self.regions.current;
|
||||||
self.cts = Constraints::new(self.regions.expand);
|
|
||||||
self.cts.base = self.regions.base.map(Some);
|
|
||||||
self.size = Size::zero();
|
self.size = Size::zero();
|
||||||
|
self.cts = Constraints::new(self.regions.expand);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the last region and return the built frames.
|
/// Finish the last region and return the built frames.
|
||||||
|
@ -43,7 +43,8 @@ impl Layout for PlacedNode {
|
|||||||
// The pod is the base area of the region because for absolute
|
// The pod is the base area of the region because for absolute
|
||||||
// placement we don't really care about the already used area (current).
|
// placement we don't really care about the already used area (current).
|
||||||
let pod = {
|
let pod = {
|
||||||
let expand = if out_of_flow { Spec::splat(true) } else { regions.expand };
|
let finite = regions.base.map(Length::is_finite);
|
||||||
|
let expand = finite & (regions.expand | out_of_flow);
|
||||||
Regions::one(regions.base, regions.base, expand)
|
Regions::one(regions.base, regions.base, expand)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::f64::consts::SQRT_2;
|
use std::f64::consts::SQRT_2;
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use crate::util::RcExt;
|
|
||||||
|
|
||||||
/// `rect`: A rectangle with optional content.
|
/// `rect`: A rectangle with optional content.
|
||||||
pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
pub fn rect(_: &mut EvalContext, args: &mut Args) -> TypResult<Value> {
|
||||||
@ -68,7 +67,13 @@ fn shape_impl(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Shorthand for padding.
|
// Shorthand for padding.
|
||||||
let padding = Sides::splat(args.named("padding")?.unwrap_or_default());
|
let mut padding = args.named::<Linear>("padding")?.unwrap_or_default();
|
||||||
|
|
||||||
|
// Padding with this ratio ensures that a rectangular child fits
|
||||||
|
// perfectly into a circle / an ellipse.
|
||||||
|
if kind.is_round() {
|
||||||
|
padding.rel += Relative::new(0.5 - SQRT_2 / 4.0);
|
||||||
|
}
|
||||||
|
|
||||||
// The shape's contents.
|
// The shape's contents.
|
||||||
let body = args.find::<Template>();
|
let body = args.find::<Template>();
|
||||||
@ -78,7 +83,9 @@ fn shape_impl(
|
|||||||
kind,
|
kind,
|
||||||
fill,
|
fill,
|
||||||
stroke,
|
stroke,
|
||||||
child: body.as_ref().map(|body| body.pack(style).padded(padding)),
|
child: body
|
||||||
|
.as_ref()
|
||||||
|
.map(|body| body.pack(style).padded(Sides::splat(padding))),
|
||||||
}
|
}
|
||||||
.pack()
|
.pack()
|
||||||
.sized(Spec::new(width, height))
|
.sized(Spec::new(width, height))
|
||||||
@ -98,84 +105,49 @@ pub struct ShapeNode {
|
|||||||
pub child: Option<PackedNode>,
|
pub child: Option<PackedNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of a shape.
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub enum ShapeKind {
|
|
||||||
/// A rectangle with equal side lengths.
|
|
||||||
Square,
|
|
||||||
/// A quadrilateral with four right angles.
|
|
||||||
Rect,
|
|
||||||
/// An ellipse with coinciding foci.
|
|
||||||
Circle,
|
|
||||||
/// A curve around two focal points.
|
|
||||||
Ellipse,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Layout for ShapeNode {
|
impl Layout for ShapeNode {
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
ctx: &mut LayoutContext,
|
ctx: &mut LayoutContext,
|
||||||
regions: &Regions,
|
regions: &Regions,
|
||||||
) -> Vec<Constrained<Rc<Frame>>> {
|
) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
// Layout, either with or without child.
|
let mut frames;
|
||||||
let mut frame = if let Some(child) = &self.child {
|
if let Some(child) = &self.child {
|
||||||
let mut node: &dyn Layout = child;
|
let mut pod = Regions::one(regions.current, regions.base, regions.expand);
|
||||||
|
frames = child.layout(ctx, &pod);
|
||||||
|
|
||||||
let storage;
|
|
||||||
if matches!(self.kind, ShapeKind::Circle | ShapeKind::Ellipse) {
|
|
||||||
// Padding with this ratio ensures that a rectangular child fits
|
|
||||||
// perfectly into a circle / an ellipse.
|
|
||||||
let ratio = Relative::new(0.5 - SQRT_2 / 4.0);
|
|
||||||
storage = child.clone().padded(Sides::splat(ratio.into()));
|
|
||||||
node = &storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, layout the child.
|
|
||||||
let mut frames = node.layout(ctx, regions);
|
|
||||||
|
|
||||||
if matches!(self.kind, ShapeKind::Square | ShapeKind::Circle) {
|
|
||||||
// Relayout with full expansion into square region to make sure
|
// Relayout with full expansion into square region to make sure
|
||||||
// the result is really a square or circle.
|
// the result is really a square or circle.
|
||||||
|
if self.kind.is_quadratic() {
|
||||||
let size = frames[0].item.size;
|
let size = frames[0].item.size;
|
||||||
let mut pod = regions.clone();
|
let desired = size.x.max(size.y);
|
||||||
pod.current.x = size.x.max(size.y).min(pod.current.x);
|
let limit = regions.current.x.min(regions.current.y);
|
||||||
pod.current.y = pod.current.x;
|
pod.current = Size::splat(desired.min(limit));
|
||||||
pod.expand = Spec::splat(true);
|
pod.expand = Spec::splat(true);
|
||||||
frames = node.layout(ctx, &pod);
|
frames = child.layout(ctx, &pod);
|
||||||
|
frames[0].cts = Constraints::tight(regions);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The default size that a shape takes on if it has no child and
|
||||||
|
// enough space.
|
||||||
|
let mut default = Size::splat(Length::pt(30.0));
|
||||||
|
if !self.kind.is_quadratic() {
|
||||||
|
default.x *= 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: What if there are multiple or no frames?
|
let mut size =
|
||||||
// Extract the frame.
|
regions.expand.select(regions.current, default).min(regions.current);
|
||||||
Rc::take(frames.into_iter().next().unwrap().item)
|
|
||||||
} else {
|
|
||||||
// When there's no child, fill the area if expansion is on,
|
|
||||||
// otherwise fall back to a default size.
|
|
||||||
let default = Length::pt(30.0);
|
|
||||||
let mut size = Size::new(
|
|
||||||
if regions.expand.x {
|
|
||||||
regions.current.x
|
|
||||||
} else {
|
|
||||||
// For rectangle and ellipse, the default shape is a bit
|
|
||||||
// wider than high.
|
|
||||||
match self.kind {
|
|
||||||
ShapeKind::Square | ShapeKind::Circle => default,
|
|
||||||
ShapeKind::Rect | ShapeKind::Ellipse => 1.5 * default,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
if regions.expand.y { regions.current.y } else { default },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Don't overflow the region.
|
// Make sure the result is really a square or circle.
|
||||||
size.x = size.x.min(regions.current.x);
|
if self.kind.is_quadratic() {
|
||||||
size.y = size.y.min(regions.current.y);
|
|
||||||
|
|
||||||
if matches!(self.kind, ShapeKind::Square | ShapeKind::Circle) {
|
|
||||||
size.x = size.x.min(size.y);
|
size.x = size.x.min(size.y);
|
||||||
size.y = size.x;
|
size.y = size.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::new(size)
|
frames = vec![Frame::new(size).constrain(Constraints::tight(regions))];
|
||||||
};
|
}
|
||||||
|
|
||||||
|
let frame = Rc::make_mut(&mut frames.last_mut().unwrap().item);
|
||||||
|
|
||||||
// Add fill and/or stroke.
|
// Add fill and/or stroke.
|
||||||
if self.fill.is_some() || self.stroke.is_some() {
|
if self.fill.is_some() || self.stroke.is_some() {
|
||||||
@ -194,9 +166,34 @@ impl Layout for ShapeNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure frame size matches regions size if expansion is on.
|
// Ensure frame size matches regions size if expansion is on.
|
||||||
frame.size = regions.expand.select(regions.current, frame.size);
|
let target = regions.expand.select(regions.current, frame.size);
|
||||||
|
frame.resize(target, Align::LEFT_TOP);
|
||||||
|
|
||||||
// Return tight constraints for now.
|
frames
|
||||||
vec![frame.constrain(Constraints::tight(regions))]
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type of a shape.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub enum ShapeKind {
|
||||||
|
/// A rectangle with equal side lengths.
|
||||||
|
Square,
|
||||||
|
/// A quadrilateral with four right angles.
|
||||||
|
Rect,
|
||||||
|
/// An ellipse with coinciding foci.
|
||||||
|
Circle,
|
||||||
|
/// A curve around two focal points.
|
||||||
|
Ellipse,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShapeKind {
|
||||||
|
/// Whether the shape is curved.
|
||||||
|
pub fn is_round(self) -> bool {
|
||||||
|
matches!(self, Self::Circle | Self::Ellipse)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the shape has a fixed 1-1 aspect ratio.
|
||||||
|
pub fn is_quadratic(self) -> bool {
|
||||||
|
matches!(self, Self::Square | Self::Circle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,14 +56,18 @@ impl Layout for SizedNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut frames = self.child.layout(ctx, &pod);
|
let mut frames = self.child.layout(ctx, &pod);
|
||||||
let Constrained { cts, .. } = &mut frames[0];
|
let Constrained { item: frame, cts } = &mut frames[0];
|
||||||
|
|
||||||
|
// Ensure frame size matches regions size if expansion is on.
|
||||||
|
let target = regions.expand.select(regions.current, frame.size);
|
||||||
|
Rc::make_mut(frame).resize(target, Align::LEFT_TOP);
|
||||||
|
|
||||||
// Set base & exact constraints if the child is automatically sized
|
// Set base & exact constraints if the child is automatically sized
|
||||||
// since we don't know what the child might have done. Also set base if
|
// since we don't know what the child might have done. Also set base if
|
||||||
// our sizing is relative.
|
// our sizing is relative.
|
||||||
*cts = Constraints::new(regions.expand);
|
*cts = Constraints::new(regions.expand);
|
||||||
cts.exact = regions.current.filter(is_auto);
|
cts.exact = regions.current.filter(regions.expand | is_auto);
|
||||||
cts.base = regions.base.filter(is_auto | is_rel);
|
cts.base = regions.base.filter(is_rel | is_auto);
|
||||||
|
|
||||||
frames
|
frames
|
||||||
}
|
}
|
||||||
|
@ -148,10 +148,6 @@ impl<'a> StackLayouter<'a> {
|
|||||||
/// Layout all children.
|
/// Layout all children.
|
||||||
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
fn layout(mut self, ctx: &mut LayoutContext) -> Vec<Constrained<Rc<Frame>>> {
|
||||||
for child in &self.stack.children {
|
for child in &self.stack.children {
|
||||||
if self.regions.is_full() {
|
|
||||||
self.finish_region();
|
|
||||||
}
|
|
||||||
|
|
||||||
match *child {
|
match *child {
|
||||||
StackChild::Spacing(Spacing::Linear(v)) => {
|
StackChild::Spacing(Spacing::Linear(v)) => {
|
||||||
self.layout_absolute(v);
|
self.layout_absolute(v);
|
||||||
@ -161,6 +157,10 @@ impl<'a> StackLayouter<'a> {
|
|||||||
self.fr += v;
|
self.fr += v;
|
||||||
}
|
}
|
||||||
StackChild::Node(ref node) => {
|
StackChild::Node(ref node) => {
|
||||||
|
if self.regions.is_full() {
|
||||||
|
self.finish_region();
|
||||||
|
}
|
||||||
|
|
||||||
self.layout_node(ctx, node);
|
self.layout_node(ctx, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@ -27,7 +27,7 @@
|
|||||||
]
|
]
|
||||||
|
|
||||||
---
|
---
|
||||||
// Test required height overflowing page.
|
// Test that square does not overflow page.
|
||||||
#page(width: 100pt, height: 75pt)
|
#page(width: 100pt, height: 75pt)
|
||||||
#square(fill: conifer)[
|
#square(fill: conifer)[
|
||||||
But, soft! what light through yonder window breaks?
|
But, soft! what light through yonder window breaks?
|
||||||
|
Loading…
x
Reference in New Issue
Block a user