summaryrefslogtreecommitdiff
path: root/crates/typst-library
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-07-19 12:53:36 +0200
committerGitHub <noreply@github.com>2023-07-19 12:53:36 +0200
commit3dcd8e6e6beb8c410e55141ca4fbc840679a1f14 (patch)
tree65e9c2c73443e471100a30c096a2424dfdd313e8 /crates/typst-library
parentb37c1e27314ed9b9341dd82c1bbc8238121c7578 (diff)
Positions placed elements relative to real container size (#1745)
This positions placed elements relative to the real container size instead of relative to the base size of the region. This makes its usage more versatile. Fixes #82 Fixes #685 Fixes #1705
Diffstat (limited to 'crates/typst-library')
-rw-r--r--crates/typst-library/src/layout/flow.rs46
-rw-r--r--crates/typst-library/src/layout/mod.rs3
-rw-r--r--crates/typst-library/src/layout/place.rs29
3 files changed, 39 insertions, 39 deletions
diff --git a/crates/typst-library/src/layout/flow.rs b/crates/typst-library/src/layout/flow.rs
index ce276f6d..930857e7 100644
--- a/crates/typst-library/src/layout/flow.rs
+++ b/crates/typst-library/src/layout/flow.rs
@@ -66,6 +66,8 @@ impl Layout for FlowElem {
sticky: true,
movable: false,
});
+ } else if let Some(placed) = child.to::<PlaceElem>() {
+ layouter.layout_placed(vt, placed, styles)?;
} else if child.can::<dyn Layout>() {
layouter.layout_multiple(vt, child, styles)?;
} else if child.is::<ColbreakElem>() {
@@ -128,7 +130,13 @@ enum FlowItem {
/// (to keep it together with its footnotes).
Frame { frame: Frame, aligns: Axes<Align>, sticky: bool, movable: bool },
/// An absolutely placed frame.
- Placed { frame: Frame, y_align: Smart<Option<Align>>, float: bool, clearance: Abs },
+ Placed {
+ frame: Frame,
+ x_align: Align,
+ y_align: Smart<Option<Align>>,
+ float: bool,
+ clearance: Abs,
+ },
/// A footnote frame (can also be the separator).
Footnote(Frame),
}
@@ -258,6 +266,25 @@ impl<'a> FlowLayouter<'a> {
Ok(())
}
+ /// Layout a placed element.
+ fn layout_placed(
+ &mut self,
+ vt: &mut Vt,
+ placed: &PlaceElem,
+ styles: StyleChain,
+ ) -> SourceResult<()> {
+ let float = placed.float(styles);
+ let clearance = placed.clearance(styles);
+ let alignment = placed.alignment(styles);
+ let x_align = alignment.map_or(Align::Center, |aligns| {
+ aligns.x.unwrap_or(GenAlign::Start).resolve(styles)
+ });
+ let y_align = alignment.map(|align| align.y.resolve(styles));
+ let frame = placed.layout(vt, styles, self.regions)?.into_frame();
+ let item = FlowItem::Placed { frame, x_align, y_align, float, clearance };
+ self.layout_item(vt, item)
+ }
+
/// Layout into multiple regions.
fn layout_multiple(
&mut self,
@@ -265,16 +292,6 @@ impl<'a> FlowLayouter<'a> {
block: &Content,
styles: StyleChain,
) -> SourceResult<()> {
- // Handle placed elements.
- if let Some(placed) = block.to::<PlaceElem>() {
- let float = placed.float(styles);
- let clearance = placed.clearance(styles);
- let y_align = placed.alignment(styles).map(|align| align.y.resolve(styles));
- let frame = placed.layout_inner(vt, styles, self.regions)?.into_frame();
- let item = FlowItem::Placed { frame, y_align, float, clearance };
- return self.layout_item(vt, item);
- }
-
// Temporarily delegerate rootness to the columns.
let is_root = self.root;
if is_root && block.is::<ColumnsElem>() {
@@ -491,7 +508,8 @@ impl<'a> FlowLayouter<'a> {
offset += frame.height();
output.push_frame(pos, frame);
}
- FlowItem::Placed { frame, y_align, float, .. } => {
+ FlowItem::Placed { frame, x_align, y_align, float, .. } => {
+ let x = x_align.position(size.x - frame.width());
let y = if float {
match y_align {
Smart::Custom(Some(Align::Top)) => {
@@ -505,7 +523,7 @@ impl<'a> FlowLayouter<'a> {
float_bottom_offset += frame.height();
y
}
- _ => offset + ruler.position(size.y - used.y),
+ _ => unreachable!("float must be y aligned"),
}
} else {
match y_align {
@@ -516,7 +534,7 @@ impl<'a> FlowLayouter<'a> {
}
};
- output.push_frame(Point::with_y(y), frame);
+ output.push_frame(Point::new(x, y), frame);
}
FlowItem::Footnote(frame) => {
let y = size.y - footnote_height + footnote_offset;
diff --git a/crates/typst-library/src/layout/mod.rs b/crates/typst-library/src/layout/mod.rs
index 41490eb8..ce728ccb 100644
--- a/crates/typst-library/src/layout/mod.rs
+++ b/crates/typst-library/src/layout/mod.rs
@@ -266,6 +266,8 @@ fn realize_block<'a>(
content: &'a Content,
styles: StyleChain<'a>,
) -> SourceResult<(Content, StyleChain<'a>)> {
+ // These elements implement `Layout` but still require a flow for
+ // proper layout.
if content.can::<dyn Layout>()
&& !content.is::<LineElem>()
&& !content.is::<RectElem>()
@@ -275,6 +277,7 @@ fn realize_block<'a>(
&& !content.is::<ImageElem>()
&& !content.is::<PolygonElem>()
&& !content.is::<PathElem>()
+ && !content.is::<PlaceElem>()
&& !applicable(content, styles)
{
return Ok((content.clone(), styles));
diff --git a/crates/typst-library/src/layout/place.rs b/crates/typst-library/src/layout/place.rs
index 6f2681c1..115e5107 100644
--- a/crates/typst-library/src/layout/place.rs
+++ b/crates/typst-library/src/layout/place.rs
@@ -92,35 +92,12 @@ impl Layout for PlaceElem {
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
- let mut frame = self.layout_inner(vt, styles, regions)?.into_frame();
-
- // If expansion is off, zero all sizes so that we don't take up any
- // space in our parent. Otherwise, respect the expand settings.
- let target = regions.expand.select(regions.size, Size::zero());
- frame.resize(target, Align::LEFT_TOP);
-
- Ok(Fragment::frame(frame))
- }
-}
-
-impl PlaceElem {
- /// Layout without zeroing the frame size.
- pub fn layout_inner(
- &self,
- vt: &mut Vt,
- styles: StyleChain,
- regions: Regions,
- ) -> SourceResult<Fragment> {
// The pod is the base area of the region because for absolute
// placement we don't really care about the already used area.
let base = regions.base();
- let expand =
- Axes::new(base.x.is_finite(), base.y.is_finite() && !self.float(styles));
-
- let pod = Regions::one(base, expand);
-
let float = self.float(styles);
let alignment = self.alignment(styles);
+
if float
&& !matches!(
alignment,
@@ -145,7 +122,9 @@ impl PlaceElem {
alignment.unwrap_or_else(|| Axes::with_x(Some(Align::Center.into()))),
);
- child.layout(vt, styles, pod)
+ let pod = Regions::one(base, Axes::splat(false));
+ let frame = child.layout(vt, styles, pod)?.into_frame();
+ Ok(Fragment::frame(frame))
}
}