summaryrefslogtreecommitdiff
path: root/library/src/layout/container.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-11-03 11:44:53 +0100
committerLaurenz <laurmaedje@gmail.com>2022-11-03 13:35:39 +0100
commit37a7afddfaffd44cb9bc013c9506599267e08983 (patch)
tree20e7d62d3c5418baff01a21d0406b91bf3096214 /library/src/layout/container.rs
parent56342bd972a13ffe21beaf2b87ab7eb1597704b4 (diff)
Split crates
Diffstat (limited to 'library/src/layout/container.rs')
-rw-r--r--library/src/layout/container.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/library/src/layout/container.rs b/library/src/layout/container.rs
new file mode 100644
index 00000000..d65b78b6
--- /dev/null
+++ b/library/src/layout/container.rs
@@ -0,0 +1,80 @@
+use crate::prelude::*;
+
+/// An inline-level container that sizes content.
+#[derive(Debug, Clone, Hash)]
+pub struct BoxNode {
+ /// How to size the content horizontally and vertically.
+ pub sizing: Axes<Option<Rel<Length>>>,
+ /// The content to be sized.
+ pub child: Content,
+}
+
+#[node(LayoutInline)]
+impl BoxNode {
+ fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
+ let width = args.named("width")?;
+ let height = args.named("height")?;
+ let body = args.eat::<Content>()?.unwrap_or_default();
+ Ok(body.boxed(Axes::new(width, height)))
+ }
+}
+
+impl LayoutInline for BoxNode {
+ fn layout_inline(
+ &self,
+ world: Tracked<dyn World>,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> SourceResult<Vec<Frame>> {
+ // The "pod" is the region into which the child will be layouted.
+ let pod = {
+ // Resolve the sizing to a concrete size.
+ let size = self
+ .sizing
+ .resolve(styles)
+ .zip(regions.base)
+ .map(|(s, b)| s.map(|v| v.relative_to(b)))
+ .unwrap_or(regions.first);
+
+ // Select the appropriate base and expansion for the child depending
+ // on whether it is automatically or relatively sized.
+ let is_auto = self.sizing.as_ref().map(Option::is_none);
+ let base = is_auto.select(regions.base, size);
+ let expand = regions.expand | !is_auto;
+
+ Regions::one(size, base, expand)
+ };
+
+ // Layout the child.
+ let mut frames = self.child.layout_inline(world, &pod, styles)?;
+
+ // Ensure frame size matches regions size if expansion is on.
+ let frame = &mut frames[0];
+ let target = regions.expand.select(regions.first, frame.size());
+ frame.resize(target, Align::LEFT_TOP);
+
+ Ok(frames)
+ }
+}
+
+/// A block-level container that places content into a separate flow.
+#[derive(Debug, Clone, Hash)]
+pub struct BlockNode(pub Content);
+
+#[node(LayoutBlock)]
+impl BlockNode {
+ fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> {
+ Ok(Self(args.eat()?.unwrap_or_default()).pack())
+ }
+}
+
+impl LayoutBlock for BlockNode {
+ fn layout_block(
+ &self,
+ world: Tracked<dyn World>,
+ regions: &Regions,
+ styles: StyleChain,
+ ) -> SourceResult<Vec<Frame>> {
+ self.0.layout_block(world, regions, styles)
+ }
+}