diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-10-28 16:43:38 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-10-28 16:43:38 +0200 |
| commit | 95e9134a3c7d7a14d8c8928413fdffc665671895 (patch) | |
| tree | 822b5f6c2d23aba33cfe4d199405e493e37c3d70 /src/library/layout | |
| parent | 66030ae5d73d85a0463562230b87f8ec7554c746 (diff) | |
Refactor `geom` module
Diffstat (limited to 'src/library/layout')
| -rw-r--r-- | src/library/layout/align.rs | 10 | ||||
| -rw-r--r-- | src/library/layout/columns.rs | 8 | ||||
| -rw-r--r-- | src/library/layout/container.rs | 2 | ||||
| -rw-r--r-- | src/library/layout/flow.rs | 18 | ||||
| -rw-r--r-- | src/library/layout/grid.rs | 77 | ||||
| -rw-r--r-- | src/library/layout/pad.rs | 6 | ||||
| -rw-r--r-- | src/library/layout/page.rs | 25 | ||||
| -rw-r--r-- | src/library/layout/place.rs | 6 | ||||
| -rw-r--r-- | src/library/layout/spacing.rs | 16 | ||||
| -rw-r--r-- | src/library/layout/stack.rs | 65 | ||||
| -rw-r--r-- | src/library/layout/transform.rs | 8 |
11 files changed, 137 insertions, 104 deletions
diff --git a/src/library/layout/align.rs b/src/library/layout/align.rs index 705d555b..95f5c01f 100644 --- a/src/library/layout/align.rs +++ b/src/library/layout/align.rs @@ -5,7 +5,7 @@ use crate::library::text::{HorizontalAlign, ParNode}; #[derive(Debug, Hash)] pub struct AlignNode { /// How to align the node horizontally and vertically. - pub aligns: Spec<Option<RawAlign>>, + pub aligns: Axes<Option<RawAlign>>, /// The node to be aligned. pub child: LayoutNode, } @@ -13,11 +13,11 @@ pub struct AlignNode { #[node] impl AlignNode { fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { - let aligns: Spec<Option<RawAlign>> = args.find()?.unwrap_or_default(); + let aligns: Axes<Option<RawAlign>> = args.find()?.unwrap_or_default(); let body: Content = args.expect("body")?; Ok(match (body, aligns) { (Content::Block(node), _) => Content::Block(node.aligned(aligns)), - (other, Spec { x: Some(x), y: None }) => { + (other, Axes { x: Some(x), y: None }) => { other.styled(ParNode::ALIGN, HorizontalAlign(x)) } (other, _) => Content::Block(other.pack().aligned(aligns)), @@ -34,7 +34,7 @@ impl Layout for AlignNode { ) -> SourceResult<Vec<Frame>> { // The child only needs to expand along an axis if there's no alignment. let mut pod = regions.clone(); - pod.expand &= self.aligns.map_is_none(); + pod.expand &= self.aligns.as_ref().map(Option::is_none); // Align paragraphs inside the child. let mut passed = StyleMap::new(); @@ -51,7 +51,7 @@ impl Layout for AlignNode { let aligns = self .aligns .map(|align| align.resolve(styles)) - .unwrap_or(Spec::new(Align::Left, Align::Top)); + .unwrap_or(Axes::new(Align::Left, Align::Top)); frame.resize(target, aligns); } diff --git a/src/library/layout/columns.rs b/src/library/layout/columns.rs index 8ae4394e..3ba3598c 100644 --- a/src/library/layout/columns.rs +++ b/src/library/layout/columns.rs @@ -15,7 +15,7 @@ pub struct ColumnsNode { impl ColumnsNode { /// The size of the gutter space between each column. #[property(resolve)] - pub const GUTTER: Relative<RawLength> = Ratio::new(0.04).into(); + pub const GUTTER: Rel<Length> = Ratio::new(0.04).into(); fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { Ok(Content::block(Self { @@ -53,7 +53,7 @@ impl Layout for ColumnsNode { .skip(1) .collect(), last: regions.last, - expand: Spec::new(true, regions.expand.y), + expand: Axes::new(true, regions.expand.y), }; // Layout the children. @@ -69,9 +69,9 @@ impl Layout for ColumnsNode { // Otherwise its the maximum column height for the frame. In that // case, the frame is first created with zero height and then // resized. - let height = if regions.expand.y { region.y } else { Length::zero() }; + let height = if regions.expand.y { region.y } else { Abs::zero() }; let mut output = Frame::new(Size::new(regions.first.x, height)); - let mut cursor = Length::zero(); + let mut cursor = Abs::zero(); for _ in 0 .. columns { let frame = match frames.next() { diff --git a/src/library/layout/container.rs b/src/library/layout/container.rs index 23556a2e..9b1f8f56 100644 --- a/src/library/layout/container.rs +++ b/src/library/layout/container.rs @@ -9,7 +9,7 @@ impl BoxNode { let width = args.named("width")?; let height = args.named("height")?; let body: LayoutNode = args.eat()?.unwrap_or_default(); - Ok(Content::inline(body.sized(Spec::new(width, height)))) + Ok(Content::inline(body.sized(Axes::new(width, height)))) } } diff --git a/src/library/layout/flow.rs b/src/library/layout/flow.rs index 7cb52910..1f0a2b4a 100644 --- a/src/library/layout/flow.rs +++ b/src/library/layout/flow.rs @@ -81,14 +81,14 @@ pub struct FlowLayouter { /// The regions to layout children into. regions: Regions, /// Whether the flow should expand to fill the region. - expand: Spec<bool>, + expand: Axes<bool>, /// The full size of `regions.size` that was available before we started /// subtracting. full: Size, /// The size used by the frames for the current region. used: Size, /// The sum of fractions in the current region. - fr: Fraction, + fr: Fr, /// Spacing and layouted nodes. items: Vec<FlowItem>, /// Finished frames for previous regions. @@ -98,11 +98,11 @@ pub struct FlowLayouter { /// A prepared item in a flow layout. enum FlowItem { /// Absolute spacing between other items. - Absolute(Length), + Absolute(Abs), /// Fractional spacing between other items. - Fractional(Fraction), + Fractional(Fr), /// A frame for a layouted child node and how to align it. - Frame(Frame, Spec<Align>), + Frame(Frame, Axes<Align>), /// An absolutely placed frame. Placed(Frame), } @@ -122,7 +122,7 @@ impl FlowLayouter { expand, full, used: Size::zero(), - fr: Fraction::zero(), + fr: Fr::zero(), items: vec![], finished: vec![], } @@ -169,7 +169,7 @@ impl FlowLayouter { } // How to align the node. - let aligns = Spec::new( + let aligns = Axes::new( // For non-expanding paragraphs it is crucial that we align the // whole paragraph as it is itself aligned. styles.get(ParNode::ALIGN), @@ -215,7 +215,7 @@ impl FlowLayouter { } let mut output = Frame::new(size); - let mut offset = Length::zero(); + let mut offset = Abs::zero(); let mut ruler = Align::Top; // Place all frames. @@ -245,7 +245,7 @@ impl FlowLayouter { self.regions.next(); self.full = self.regions.first; self.used = Size::zero(); - self.fr = Fraction::zero(); + self.fr = Fr::zero(); self.finished.push(output); } diff --git a/src/library/layout/grid.rs b/src/library/layout/grid.rs index 2c246df9..a1098c6d 100644 --- a/src/library/layout/grid.rs +++ b/src/library/layout/grid.rs @@ -4,9 +4,9 @@ use crate::library::prelude::*; #[derive(Debug, Hash)] pub struct GridNode { /// Defines sizing for content rows and columns. - pub tracks: Spec<Vec<TrackSizing>>, + pub tracks: Axes<Vec<TrackSizing>>, /// Defines sizing of gutter rows and columns between content. - pub gutter: Spec<Vec<TrackSizing>>, + pub gutter: Axes<Vec<TrackSizing>>, /// The nodes to be arranged in a grid. pub cells: Vec<LayoutNode>, } @@ -20,8 +20,8 @@ impl GridNode { let column_gutter = args.named("column-gutter")?; let row_gutter = args.named("row-gutter")?; Ok(Content::block(Self { - tracks: Spec::new(columns, rows), - gutter: Spec::new( + tracks: Axes::new(columns, rows), + gutter: Axes::new( column_gutter.unwrap_or_else(|| base_gutter.clone()), row_gutter.unwrap_or(base_gutter), ), @@ -59,10 +59,10 @@ pub enum TrackSizing { Auto, /// A track size specified in absolute terms and relative to the parent's /// size. - Relative(Relative<RawLength>), + Relative(Rel<Length>), /// A track size specified as a fraction of the remaining free space in the /// parent. - Fractional(Fraction), + Fractional(Fr), } castable! { @@ -105,16 +105,16 @@ pub struct GridLayouter<'a> { /// The inherited styles. styles: StyleChain<'a>, /// Resolved column sizes. - rcols: Vec<Length>, + rcols: Vec<Abs>, /// Rows in the current region. lrows: Vec<Row>, /// The full height of the current region. - full: Length, + full: Abs, /// The used-up size of the current region. The horizontal size is /// determined once after columns are resolved and not touched again. used: Size, /// The sum of fractions in the current region. - fr: Fraction, + fr: Fr, /// Frames for finished regions. finished: Vec<Frame>, } @@ -125,7 +125,7 @@ enum Row { /// Finished row frame of auto or relative row. Frame(Frame), /// Fractional row with y index. - Fr(Fraction, usize), + Fr(Fr, usize), } impl<'a> GridLayouter<'a> { @@ -134,8 +134,8 @@ impl<'a> GridLayouter<'a> { /// This prepares grid layout by unifying content and gutter tracks. pub fn new( world: Tracked<'a, dyn World>, - tracks: Spec<&[TrackSizing]>, - gutter: Spec<&[TrackSizing]>, + tracks: Axes<&[TrackSizing]>, + gutter: Axes<&[TrackSizing]>, cells: &'a [LayoutNode], regions: &Regions, styles: StyleChain<'a>, @@ -156,7 +156,7 @@ impl<'a> GridLayouter<'a> { }; let auto = TrackSizing::Auto; - let zero = TrackSizing::Relative(Relative::zero()); + let zero = TrackSizing::Relative(Rel::zero()); let get_or = |tracks: &[_], idx, default| { tracks.get(idx).or(tracks.last()).copied().unwrap_or(default) }; @@ -178,13 +178,13 @@ impl<'a> GridLayouter<'a> { rows.pop(); let full = regions.first.y; - let rcols = vec![Length::zero(); cols.len()]; + let rcols = vec![Abs::zero(); cols.len()]; let lrows = vec![]; // We use the regions for auto row measurement. Since at that moment, // columns are already sized, we can enable horizontal expansion. let mut regions = regions.clone(); - regions.expand = Spec::new(true, false); + regions.expand = Axes::new(true, false); Self { world, @@ -197,7 +197,7 @@ impl<'a> GridLayouter<'a> { lrows, full, used: Size::zero(), - fr: Fraction::zero(), + fr: Fr::zero(), finished: vec![], } } @@ -230,10 +230,10 @@ impl<'a> GridLayouter<'a> { /// Determine all column sizes. fn measure_columns(&mut self) -> SourceResult<()> { // Sum of sizes of resolved relative tracks. - let mut rel = Length::zero(); + let mut rel = Abs::zero(); // Sum of fractions of all fractional tracks. - let mut fr = Fraction::zero(); + let mut fr = Fr::zero(); // Resolve the size of all relative columns and compute the sum of all // fractional tracks. @@ -252,14 +252,14 @@ impl<'a> GridLayouter<'a> { // Size that is not used by fixed-size columns. let available = self.regions.first.x - rel; - if available >= Length::zero() { + if available >= Abs::zero() { // Determine size of auto columns. let (auto, count) = self.measure_auto_columns(available)?; // If there is remaining space, distribute it to fractional columns, // otherwise shrink auto columns. let remaining = available - auto; - if remaining >= Length::zero() { + if remaining >= Abs::zero() { if !fr.is_zero() { self.grow_fractional_columns(remaining, fr); } @@ -275,11 +275,8 @@ impl<'a> GridLayouter<'a> { } /// Measure the size that is available to auto columns. - fn measure_auto_columns( - &mut self, - available: Length, - ) -> SourceResult<(Length, usize)> { - let mut auto = Length::zero(); + fn measure_auto_columns(&mut self, available: Abs) -> SourceResult<(Abs, usize)> { + let mut auto = Abs::zero(); let mut count = 0; // Determine size of auto columns by laying out all cells in those @@ -289,12 +286,12 @@ impl<'a> GridLayouter<'a> { continue; } - let mut resolved = Length::zero(); + let mut resolved = Abs::zero(); for y in 0 .. self.rows.len() { if let Some(node) = self.cell(x, y) { let size = Size::new(available, self.regions.base.y); let mut pod = - Regions::one(size, self.regions.base, Spec::splat(false)); + Regions::one(size, self.regions.base, Axes::splat(false)); // For relative rows, we can already resolve the correct // base, for auto it's already correct and for fr we could @@ -318,7 +315,7 @@ impl<'a> GridLayouter<'a> { } /// Distribute remaining space to fractional columns. - fn grow_fractional_columns(&mut self, remaining: Length, fr: Fraction) { + fn grow_fractional_columns(&mut self, remaining: Abs, fr: Fr) { for (&col, rcol) in self.cols.iter().zip(&mut self.rcols) { if let TrackSizing::Fractional(v) = col { *rcol = v.share(fr, remaining); @@ -327,7 +324,7 @@ impl<'a> GridLayouter<'a> { } /// Redistribute space to auto columns so that each gets a fair share. - fn shrink_auto_columns(&mut self, available: Length, count: usize) { + fn shrink_auto_columns(&mut self, available: Abs, count: usize) { // The fair share each auto column may have. let fair = available / count as f64; @@ -359,7 +356,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row with automatic height. Such a row may break across multiple /// regions. fn layout_auto_row(&mut self, y: usize) -> SourceResult<()> { - let mut resolved: Vec<Length> = vec![]; + let mut resolved: Vec<Abs> = vec![]; // Determine the size for each region of the row. for (x, &rcol) in self.rcols.iter().enumerate() { @@ -426,11 +423,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row with relative height. Such a row cannot break across /// multiple regions, but it may force a region break. - fn layout_relative_row( - &mut self, - v: Relative<RawLength>, - y: usize, - ) -> SourceResult<()> { + fn layout_relative_row(&mut self, v: Rel<Length>, y: usize) -> SourceResult<()> { let resolved = v.resolve(self.styles).relative_to(self.regions.base.y); let frame = self.layout_single_row(resolved, y)?; @@ -451,7 +444,7 @@ impl<'a> GridLayouter<'a> { } /// Layout a row with fixed height and return its frame. - fn layout_single_row(&mut self, height: Length, y: usize) -> SourceResult<Frame> { + fn layout_single_row(&mut self, height: Abs, y: usize) -> SourceResult<Frame> { let mut output = Frame::new(Size::new(self.used.x, height)); let mut pos = Point::zero(); @@ -462,11 +455,11 @@ impl<'a> GridLayouter<'a> { // Set the base to the region's base for auto rows and to the // size for relative and fractional rows. - let base = Spec::new(self.cols[x], self.rows[y]) + let base = Axes::new(self.cols[x], self.rows[y]) .map(|s| s == TrackSizing::Auto) .select(self.regions.base, size); - let pod = Regions::one(size, base, Spec::splat(true)); + let pod = Regions::one(size, base, Axes::splat(true)); let frame = node.layout(self.world, &pod, self.styles)?.remove(0); match frame.role() { Some(Role::ListLabel | Role::ListItemBody) => { @@ -488,7 +481,7 @@ impl<'a> GridLayouter<'a> { /// Layout a row spanning multiple regions. fn layout_multi_row( &mut self, - heights: &[Length], + heights: &[Abs], y: usize, ) -> SourceResult<Vec<Frame>> { // Prepare frames. @@ -499,7 +492,7 @@ impl<'a> GridLayouter<'a> { // Prepare regions. let size = Size::new(self.used.x, heights[0]); - let mut pod = Regions::one(size, self.regions.base, Spec::splat(true)); + let mut pod = Regions::one(size, self.regions.base, Axes::splat(true)); pod.backlog = heights[1 ..].to_vec(); // Layout the row. @@ -573,8 +566,8 @@ impl<'a> GridLayouter<'a> { self.finished.push(output); self.regions.next(); self.full = self.regions.first.y; - self.used.y = Length::zero(); - self.fr = Fraction::zero(); + self.used.y = Abs::zero(); + self.fr = Fr::zero(); Ok(()) } diff --git a/src/library/layout/pad.rs b/src/library/layout/pad.rs index 06c3672f..b0238d40 100644 --- a/src/library/layout/pad.rs +++ b/src/library/layout/pad.rs @@ -4,7 +4,7 @@ use crate::library::prelude::*; #[derive(Debug, Hash)] pub struct PadNode { /// The amount of padding. - pub padding: Sides<Relative<RawLength>>, + pub padding: Sides<Rel<Length>>, /// The child node whose sides to pad. pub child: LayoutNode, } @@ -54,7 +54,7 @@ impl Layout for PadNode { } /// Shrink a size by padding relative to the size itself. -fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size { +fn shrink(size: Size, padding: Sides<Rel<Abs>>) -> Size { size - padding.relative_to(size).sum_by_axis() } @@ -77,7 +77,7 @@ fn shrink(size: Size, padding: Sides<Relative<Length>>) -> Size { /// <=> w - p.rel * w - p.abs = s /// <=> (1 - p.rel) * w = s + p.abs /// <=> w = (s + p.abs) / (1 - p.rel) -fn grow(size: Size, padding: Sides<Relative<Length>>) -> Size { +fn grow(size: Size, padding: Sides<Rel<Abs>>) -> Size { size.zip(padding.sum_by_axis()) .map(|(s, p)| (s + p.abs).safe_div(1.0 - p.rel.get())) } diff --git a/src/library/layout/page.rs b/src/library/layout/page.rs index 7d13163d..2e5cf2f9 100644 --- a/src/library/layout/page.rs +++ b/src/library/layout/page.rs @@ -11,17 +11,16 @@ pub struct PageNode(pub LayoutNode); impl PageNode { /// The unflipped width of the page. #[property(resolve)] - pub const WIDTH: Smart<RawLength> = Smart::Custom(Paper::A4.width().into()); + pub const WIDTH: Smart<Length> = Smart::Custom(Paper::A4.width().into()); /// The unflipped height of the page. #[property(resolve)] - pub const HEIGHT: Smart<RawLength> = Smart::Custom(Paper::A4.height().into()); + pub const HEIGHT: Smart<Length> = Smart::Custom(Paper::A4.height().into()); /// Whether the page is flipped into landscape orientation. pub const FLIPPED: bool = false; /// The page's margins. #[property(fold)] - pub const MARGINS: Sides<Option<Smart<Relative<RawLength>>>> = - Sides::splat(Smart::Auto); + pub const MARGINS: Sides<Option<Smart<Rel<Length>>>> = Sides::splat(Smart::Auto); /// How many columns the page has. pub const COLUMNS: NonZeroUsize = NonZeroUsize::new(1).unwrap(); @@ -63,8 +62,8 @@ impl PageNode { ) -> SourceResult<Vec<Frame>> { // When one of the lengths is infinite the page fits its content along // that axis. - let width = styles.get(Self::WIDTH).unwrap_or(Length::inf()); - let height = styles.get(Self::HEIGHT).unwrap_or(Length::inf()); + let width = styles.get(Self::WIDTH).unwrap_or(Abs::inf()); + let height = styles.get(Self::HEIGHT).unwrap_or(Abs::inf()); let mut size = Size::new(width, height); if styles.get(Self::FLIPPED) { std::mem::swap(&mut size.x, &mut size.y); @@ -76,7 +75,7 @@ impl PageNode { } // Determine the margins. - let default = Relative::from(0.1190 * min); + let default = Rel::from(0.1190 * min); let padding = styles.get(Self::MARGINS).map(|side| side.unwrap_or(default)); let mut child = self.0.clone(); @@ -96,7 +95,7 @@ impl PageNode { } // Layout the child. - let regions = Regions::repeat(size, size, size.map(Length::is_finite)); + let regions = Regions::repeat(size, size, size.map(Abs::is_finite)); let mut frames = child.layout(world, ®ions, styles)?; let header = styles.get(Self::HEADER); @@ -127,7 +126,7 @@ impl PageNode { (Role::Background, background, Point::zero(), size), ] { if let Some(content) = marginal.resolve(world, page)? { - let pod = Regions::one(area, area, Spec::splat(true)); + let pod = Regions::one(area, area, Axes::splat(true)); let mut sub = content.layout(world, &pod, styles)?.remove(0); sub.apply_role(role); @@ -224,13 +223,13 @@ pub struct Paper { impl Paper { /// The width of the paper. - pub fn width(self) -> Length { - Length::mm(self.width) + pub fn width(self) -> Abs { + Abs::mm(self.width) } /// The height of the paper. - pub fn height(self) -> Length { - Length::mm(self.height) + pub fn height(self) -> Abs { + Abs::mm(self.height) } } diff --git a/src/library/layout/place.rs b/src/library/layout/place.rs index 01da62e5..8b68c087 100644 --- a/src/library/layout/place.rs +++ b/src/library/layout/place.rs @@ -8,12 +8,12 @@ pub struct PlaceNode(pub LayoutNode); #[node] impl PlaceNode { fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { - let aligns = args.find()?.unwrap_or(Spec::with_x(Some(RawAlign::Start))); + let aligns = args.find()?.unwrap_or(Axes::with_x(Some(RawAlign::Start))); let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); let body: LayoutNode = args.expect("body")?; Ok(Content::block(Self( - body.moved(Spec::new(dx, dy)).aligned(aligns), + body.moved(Axes::new(dx, dy)).aligned(aligns), ))) } } @@ -30,7 +30,7 @@ impl Layout for PlaceNode { // The pod is the base area of the region because for absolute // placement we don't really care about the already used area. let pod = { - let finite = regions.base.map(Length::is_finite); + let finite = regions.base.map(Abs::is_finite); let expand = finite & (regions.expand | out_of_flow); Regions::one(regions.base, regions.base, expand) }; diff --git a/src/library/layout/spacing.rs b/src/library/layout/spacing.rs index 0c5cbb92..28e52d73 100644 --- a/src/library/layout/spacing.rs +++ b/src/library/layout/spacing.rs @@ -31,10 +31,10 @@ impl VNode { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum Spacing { /// Spacing specified in absolute terms and relative to the parent's size. - Relative(Relative<RawLength>), + Relative(Rel<Length>), /// Spacing specified as a fraction of the remaining free space in the /// parent. - Fractional(Fraction), + Fractional(Fr), } impl Spacing { @@ -44,9 +44,9 @@ impl Spacing { } } -impl From<Length> for Spacing { - fn from(length: Length) -> Self { - Self::Relative(length.into()) +impl From<Abs> for Spacing { + fn from(abs: Abs) -> Self { + Self::Relative(abs.into()) } } @@ -71,12 +71,12 @@ castable! { /// Spacing around and between block-level nodes, relative to paragraph spacing. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct BlockSpacing(Relative<RawLength>); +pub struct BlockSpacing(Rel<Length>); -castable!(BlockSpacing: Relative<RawLength>); +castable!(BlockSpacing: Rel<Length>); impl Resolve for BlockSpacing { - type Output = Length; + type Output = Abs; fn resolve(self, styles: StyleChain) -> Self::Output { let whole = styles.get(ParNode::SPACING); diff --git a/src/library/layout/stack.rs b/src/library/layout/stack.rs index b9a26642..b9663dd6 100644 --- a/src/library/layout/stack.rs +++ b/src/library/layout/stack.rs @@ -90,19 +90,19 @@ pub struct StackLayouter<'a> { /// The stacking direction. dir: Dir, /// The axis of the stacking direction. - axis: SpecAxis, + axis: Axis, /// The regions to layout children into. regions: Regions, /// The inherited styles. styles: StyleChain<'a>, /// Whether the stack itself should expand to fill the region. - expand: Spec<bool>, + expand: Axes<bool>, /// The full size of the current region that was available at the start. full: Size, /// The generic size used by the frames for the current region. - used: Gen<Length>, + used: Gen<Abs>, /// The sum of fractions in the current region. - fr: Fraction, + fr: Fr, /// Already layouted items whose exact positions are not yet known due to /// fractional spacing. items: Vec<StackItem>, @@ -113,9 +113,9 @@ pub struct StackLayouter<'a> { /// A prepared item in a stack layout. enum StackItem { /// Absolute spacing between other items. - Absolute(Length), + Absolute(Abs), /// Fractional spacing between other items. - Fractional(Fraction), + Fractional(Fr), /// A frame for a layouted child node. Frame(Frame, Align), } @@ -139,7 +139,7 @@ impl<'a> StackLayouter<'a> { expand, full, used: Gen::zero(), - fr: Fraction::zero(), + fr: Fr::zero(), items: vec![], finished: vec![], } @@ -200,7 +200,12 @@ impl<'a> StackLayouter<'a> { frame.apply_role(Role::GenericBlock); // Grow our size, shrink the region and save the frame for later. - let size = frame.size().to_gen(self.axis); + let size = frame.size(); + let size = match self.axis { + Axis::X => Gen::new(size.y, size.x), + Axis::Y => Gen::new(size.x, size.y), + }; + self.used.main += size.main; self.used.cross.set_max(size.cross); *self.regions.first.get_mut(self.axis) -= size.main; @@ -218,7 +223,7 @@ impl<'a> StackLayouter<'a> { pub fn finish_region(&mut self) { // Determine the size of the stack in this region dependening on whether // the region expands. - let used = self.used.to_spec(self.axis); + let used = self.used.to_axes(self.axis); let mut size = self.expand.select(self.full, used); // Expand fully if there are fr spacings. @@ -230,7 +235,7 @@ impl<'a> StackLayouter<'a> { } let mut output = Frame::new(size); - let mut cursor = Length::zero(); + let mut cursor = Abs::zero(); let mut ruler: Align = self.dir.start().into(); // Place all frames. @@ -255,7 +260,7 @@ impl<'a> StackLayouter<'a> { self.used.main - child - cursor }; - let pos = Gen::new(Length::zero(), block).to_point(self.axis); + let pos = Gen::new(Abs::zero(), block).to_point(self.axis); cursor += child; output.push_frame(pos, frame); } @@ -266,7 +271,7 @@ impl<'a> StackLayouter<'a> { self.regions.next(); self.full = self.regions.first; self.used = Gen::zero(); - self.fr = Fraction::zero(); + self.fr = Fr::zero(); self.finished.push(output); } @@ -276,3 +281,39 @@ impl<'a> StackLayouter<'a> { self.finished } } + +/// A container with a main and cross component. +#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] +pub struct Gen<T> { + /// The main component. + pub cross: T, + /// The cross component. + pub main: T, +} + +impl<T> Gen<T> { + /// Create a new instance from the two components. + pub const fn new(cross: T, main: T) -> Self { + Self { cross, main } + } + + /// Convert to the specific representation, given the current main axis. + pub fn to_axes(self, main: Axis) -> Axes<T> { + match main { + Axis::X => Axes::new(self.main, self.cross), + Axis::Y => Axes::new(self.cross, self.main), + } + } +} + +impl Gen<Abs> { + /// The zero value. + pub fn zero() -> Self { + Self { cross: Abs::zero(), main: Abs::zero() } + } + + /// Convert to a point. + pub fn to_point(self, main: Axis) -> Point { + self.to_axes(main).to_point() + } +} diff --git a/src/library/layout/transform.rs b/src/library/layout/transform.rs index b110f343..ff42744a 100644 --- a/src/library/layout/transform.rs +++ b/src/library/layout/transform.rs @@ -5,7 +5,7 @@ use crate::library::prelude::*; #[derive(Debug, Hash)] pub struct MoveNode { /// The offset by which to move the node. - pub delta: Spec<Relative<RawLength>>, + pub delta: Axes<Rel<Length>>, /// The node whose contents should be moved. pub child: LayoutNode, } @@ -16,7 +16,7 @@ impl MoveNode { let dx = args.named("dx")?.unwrap_or_default(); let dy = args.named("dy")?.unwrap_or_default(); Ok(Content::inline(Self { - delta: Spec::new(dx, dy), + delta: Axes::new(dx, dy), child: args.expect("body")?, })) } @@ -60,7 +60,7 @@ pub type ScaleNode = TransformNode<SCALE>; impl<const T: TransformKind> TransformNode<T> { /// The origin of the transformation. #[property(resolve)] - pub const ORIGIN: Spec<Option<RawAlign>> = Spec::default(); + pub const ORIGIN: Axes<Option<RawAlign>> = Axes::default(); fn construct(_: &mut Vm, args: &mut Args) -> SourceResult<Content> { let transform = match T { @@ -94,7 +94,7 @@ impl<const T: TransformKind> Layout for TransformNode<T> { let mut frames = self.child.layout(world, regions, styles)?; for frame in &mut frames { - let Spec { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s)); + let Axes { x, y } = origin.zip(frame.size()).map(|(o, s)| o.position(s)); let transform = Transform::translate(x, y) .pre_concat(self.transform) .pre_concat(Transform::translate(-x, -y)); |
