diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-10 22:19:36 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-10 22:19:36 +0200 |
| commit | 92c01da36016e94ff20163806ddcbcf7e33d4031 (patch) | |
| tree | 1a900b3c11edcc93e9153fada3ce92310db5768b /src/layout | |
| parent | 42500d5ed85539c5ab04dd3544beaf802da29be9 (diff) | |
Switch back to custom geometry types, unified with layout primitives 🏞
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/document.rs (renamed from src/layout/nodes/document.rs) | 2 | ||||
| -rw-r--r-- | src/layout/fixed.rs (renamed from src/layout/nodes/fixed.rs) | 0 | ||||
| -rw-r--r-- | src/layout/mod.rs | 29 | ||||
| -rw-r--r-- | src/layout/node.rs (renamed from src/layout/nodes/mod.rs) | 18 | ||||
| -rw-r--r-- | src/layout/pad.rs (renamed from src/layout/nodes/pad.rs) | 10 | ||||
| -rw-r--r-- | src/layout/par.rs (renamed from src/layout/nodes/par.rs) | 146 | ||||
| -rw-r--r-- | src/layout/primitive.rs | 510 | ||||
| -rw-r--r-- | src/layout/spacing.rs (renamed from src/layout/nodes/spacing.rs) | 2 | ||||
| -rw-r--r-- | src/layout/stack.rs (renamed from src/layout/nodes/stack.rs) | 34 | ||||
| -rw-r--r-- | src/layout/text.rs (renamed from src/layout/nodes/text.rs) | 4 |
10 files changed, 107 insertions, 648 deletions
diff --git a/src/layout/nodes/document.rs b/src/layout/document.rs index 5c7a2410..c2d7b38b 100644 --- a/src/layout/nodes/document.rs +++ b/src/layout/document.rs @@ -1,6 +1,6 @@ use super::*; -/// The top-level layouting node. +/// The top-level layout node. #[derive(Debug, Clone, PartialEq)] pub struct Document { pub runs: Vec<Pages>, diff --git a/src/layout/nodes/fixed.rs b/src/layout/fixed.rs index 0d438879..0d438879 100644 --- a/src/layout/nodes/fixed.rs +++ b/src/layout/fixed.rs diff --git a/src/layout/mod.rs b/src/layout/mod.rs index bfd633d8..2368c441 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,17 +1,28 @@ //! Layouting of documents. -pub mod nodes; -pub mod primitive; - -pub use primitive::*; +mod document; +mod fixed; +mod node; +mod pad; +mod par; +mod spacing; +mod stack; +mod text; use async_trait::async_trait; use crate::font::SharedFontLoader; -use crate::geom::{Point, Rect, Size, SizeExt}; +use crate::geom::*; use crate::shaping::Shaped; -use nodes::Document; +pub use document::*; +pub use fixed::*; +pub use node::*; +pub use pad::*; +pub use par::*; +pub use spacing::*; +pub use stack::*; +pub use text::*; /// Layout a document and return the produced layouts. pub async fn layout(document: &Document, loader: SharedFontLoader) -> Vec<BoxLayout> { @@ -53,9 +64,9 @@ pub trait Layout { #[derive(Debug, Clone, PartialEq)] pub enum LayoutItem { /// Spacing that should be added to the parent. - Spacing(f64), + Spacing(Length), /// A box that should be aligned in the parent. - Box(BoxLayout, Gen2<GenAlign>), + Box(BoxLayout, Gen<Align>), } /// The constraints for layouting a single node. @@ -101,7 +112,7 @@ impl BoxLayout { /// given position. pub fn push_layout(&mut self, pos: Point, more: Self) { for (subpos, element) in more.elements { - self.push(pos + subpos.to_vec2(), element); + self.push(pos + subpos, element); } } } diff --git a/src/layout/nodes/mod.rs b/src/layout/node.rs index a304e63c..3230621f 100644 --- a/src/layout/nodes/mod.rs +++ b/src/layout/node.rs @@ -1,27 +1,9 @@ //! Layout nodes. -mod document; -mod fixed; -mod pad; -mod par; -mod spacing; -mod stack; -mod text; - -pub use document::*; -pub use fixed::*; -pub use pad::*; -pub use par::*; -pub use spacing::*; -pub use stack::*; -pub use text::*; - use std::any::Any; use std::fmt::{self, Debug, Formatter}; use std::ops::Deref; -use async_trait::async_trait; - use super::*; /// A self-contained, styled layout node. diff --git a/src/layout/nodes/pad.rs b/src/layout/pad.rs index 10a9e2c6..2e1817b7 100644 --- a/src/layout/nodes/pad.rs +++ b/src/layout/pad.rs @@ -21,8 +21,8 @@ impl Layout for Pad { .spaces .into_iter() .map(|space| LayoutSpace { - base: space.base + self.padding.insets(space.base).size(), - size: space.size + self.padding.insets(space.size).size(), + base: space.base - self.padding.eval(space.base).size(), + size: space.size - self.padding.eval(space.size).size(), }) .collect(), repeat: constraints.repeat, @@ -31,11 +31,11 @@ impl Layout for Pad { .into_iter() .map(|item| match item { LayoutItem::Box(boxed, align) => { - let padding = self.padding.insets(boxed.size); - let padded = boxed.size - padding.size(); + let padding = self.padding.eval(boxed.size); + let padded = boxed.size + padding.size(); let mut outer = BoxLayout::new(padded); - let start = Point::new(-padding.x0, -padding.y0); + let start = Point::new(padding.left, padding.top); outer.push_layout(start, boxed); LayoutItem::Box(outer, align) diff --git a/src/layout/nodes/par.rs b/src/layout/par.rs index 082ab963..2a139760 100644 --- a/src/layout/nodes/par.rs +++ b/src/layout/par.rs @@ -7,11 +7,11 @@ use super::*; /// the main axis by the height of the previous line plus extra line spacing. #[derive(Debug, Clone, PartialEq)] pub struct Par { - pub dirs: Gen2<Dir>, - pub line_spacing: f64, + pub dirs: Gen<Dir>, + pub line_spacing: Length, pub children: Vec<LayoutNode>, - pub aligns: Gen2<GenAlign>, - pub expand: Spec2<bool>, + pub aligns: Gen<Align>, + pub expand: Spec<bool>, } #[async_trait(?Send)] @@ -73,17 +73,17 @@ struct LineLayouter { #[derive(Debug, Clone)] struct LineContext { /// The layout directions. - dirs: Gen2<Dir>, + dirs: Gen<Dir>, /// The spaces to layout into. spaces: Vec<LayoutSpace>, /// Whether to spill over into copies of the last space or finish layouting /// when the last space is used up. repeat: bool, /// The spacing to be inserted between each pair of lines. - line_spacing: f64, + line_spacing: Length, /// Whether to expand the size of the resulting layout to the full size of /// this space or to shrink it to fit the content. - expand: Spec2<bool>, + expand: Spec<bool>, } impl LineLayouter { @@ -102,7 +102,7 @@ impl LineLayouter { } /// Add a layout. - fn push_box(&mut self, layout: BoxLayout, aligns: Gen2<GenAlign>) { + fn push_box(&mut self, layout: BoxLayout, aligns: Gen<Align>) { let dirs = self.ctx.dirs; if let Some(prev) = self.run.aligns { if aligns.main != prev.main { @@ -124,9 +124,9 @@ impl LineLayouter { // FIXME: Alignment in non-expanding parent. rest_run.usable = Some(match aligns.cross { - GenAlign::Start => unreachable!("start > x"), - GenAlign::Center => usable - 2.0 * self.run.size.cross, - GenAlign::End => usable - self.run.size.cross, + Align::Start => unreachable!("start > x"), + Align::Center => usable - 2.0 * self.run.size.cross, + Align::End => usable - self.run.size.cross, }); self.finish_line(); @@ -160,7 +160,7 @@ impl LineLayouter { } /// Add spacing to the line. - fn push_spacing(&mut self, mut spacing: f64) { + fn push_spacing(&mut self, mut spacing: Length) { spacing = spacing.min(self.usable().cross); self.run.size.cross += spacing; } @@ -169,7 +169,7 @@ impl LineLayouter { /// /// This specifies how much more would fit before a line break would be /// needed. - fn usable(&self) -> Gen2<f64> { + fn usable(&self) -> Gen<Length> { // The base is the usable space of the stack layouter. let mut usable = self.stack.usable().switch(self.ctx.dirs); @@ -192,7 +192,7 @@ impl LineLayouter { /// Whether the currently set line is empty. fn line_is_empty(&self) -> bool { - self.run.size == Gen2::ZERO && self.run.layouts.is_empty() + self.run.size == Gen::ZERO && self.run.layouts.is_empty() } /// Finish everything up and return the final collection of boxes. @@ -224,7 +224,7 @@ impl LineLayouter { self.run.size.cross - offset - child.size.get(dirs.cross.axis()) }; - let pos = Gen2::new(0.0, cross).switch(dirs).to_point(); + let pos = Gen::new(Length::ZERO, cross).switch(dirs).to_point(); layout.push_layout(pos, child); } @@ -244,25 +244,25 @@ impl LineLayouter { /// multiple runs with different alignments. struct LineRun { /// The so-far accumulated items of the run. - layouts: Vec<(f64, BoxLayout)>, + layouts: Vec<(Length, BoxLayout)>, /// The summed width and maximal height of the run. - size: Gen2<f64>, + size: Gen<Length>, /// The alignment of all layouts in the line. /// /// When a new run is created the alignment is yet to be determined and /// `None` as such. Once a layout is added, its alignment decides the /// alignment for the whole run. - aligns: Option<Gen2<GenAlign>>, + aligns: Option<Gen<Align>>, /// The amount of cross-space left by another run on the same line or `None` /// if this is the only run so far. - usable: Option<f64>, + usable: Option<Length>, } impl LineRun { fn new() -> Self { Self { layouts: vec![], - size: Gen2::ZERO, + size: Gen::ZERO, aligns: None, usable: None, } @@ -283,7 +283,7 @@ pub(super) struct StackLayouter { #[derive(Debug, Clone)] pub(super) struct StackContext { /// The layouting directions. - pub dirs: Gen2<Dir>, + pub dirs: Gen<Dir>, /// The spaces to layout into. pub spaces: Vec<LayoutSpace>, /// Whether to spill over into copies of the last space or finish layouting @@ -291,7 +291,7 @@ pub(super) struct StackContext { pub repeat: bool, /// Whether to expand the size of the resulting layout to the full size of /// this space or to shrink it to fit the content. - pub expand: Spec2<bool>, + pub expand: Spec<bool>, } impl StackLayouter { @@ -306,7 +306,7 @@ impl StackLayouter { } /// Add a layout to the stack. - pub fn push_box(&mut self, layout: BoxLayout, aligns: Gen2<GenAlign>) { + pub fn push_box(&mut self, layout: BoxLayout, aligns: Gen<Align>) { // If the alignment cannot be fitted in this space, finish it. // // TODO: Issue warning for non-fitting alignment in non-repeating @@ -331,20 +331,20 @@ impl StackLayouter { } /// Add spacing to the stack. - pub fn push_spacing(&mut self, mut spacing: f64) { + pub fn push_spacing(&mut self, mut spacing: Length) { // Reduce the spacing such that it definitely fits. let axis = self.ctx.dirs.main.axis(); spacing = spacing.min(self.space.usable.get(axis)); - let size = Gen2::new(spacing, 0.0); + let size = Gen::new(spacing, Length::ZERO); self.update_metrics(size); self.space.layouts.push(( BoxLayout::new(size.switch(self.ctx.dirs).to_size()), - Gen2::default(), + Gen::default(), )); } - fn update_metrics(&mut self, added: Gen2<f64>) { + fn update_metrics(&mut self, added: Gen<Length>) { let mut used = self.space.used.switch(self.ctx.dirs); used.cross = used.cross.max(added.cross); used.main += added.main; @@ -398,11 +398,7 @@ impl StackLayouter { /// Finish active current space and start a new one. pub fn finish_space(&mut self, hard: bool) { let dirs = self.ctx.dirs; - - // ------------------------------------------------------------------ // - // Step 1: Determine the full size of the space. - // (Mostly done already while collecting the boxes, but here we - // expand if necessary.) + let main = dirs.main.axis(); let space = self.ctx.spaces[self.space.index]; let layout_size = { @@ -416,64 +412,44 @@ impl StackLayouter { used_size }; - let mut layout = BoxLayout::new(layout_size); + let mut sum = Length::ZERO; + let mut sums = Vec::with_capacity(self.space.layouts.len() + 1); - // ------------------------------------------------------------------ // - // Step 2: Forward pass. Create a bounding box for each layout in which - // it will be aligned. Then, go forwards through the boxes and remove - // what is taken by previous layouts from the following layouts. - - let mut bounds = vec![]; - let mut bound = Rect { - x0: 0.0, - y0: 0.0, - x1: layout_size.width, - y1: layout_size.height, - }; - - for (layout, _) in &self.space.layouts { - // First, store the bounds calculated so far (which were reduced - // by the predecessors of this layout) as the initial bounding box - // of this layout. - bounds.push(bound); - - // Then, reduce the bounding box for the following layouts. This - // layout uses up space from the origin to the end. Thus, it reduces - // the usable space for following layouts at its origin by its - // main-axis extent. - *bound.get_mut(dirs.main.start()) += - dirs.main.factor() * layout.size.get(dirs.main.axis()); + for (boxed, _) in &self.space.layouts { + sums.push(sum); + sum += boxed.size.get(main); } - // ------------------------------------------------------------------ // - // Step 3: Backward pass. Reduce the bounding boxes from the previous - // layouts by what is taken by the following ones. - - let mut main_extent = 0.0; - for (child, bound) in self.space.layouts.iter().zip(&mut bounds).rev() { - let (layout, _) = child; + sums.push(sum); - // Reduce the bounding box of this layout by the following one's - // main-axis extents. - *bound.get_mut(dirs.main.end()) -= dirs.main.factor() * main_extent; + let mut layout = BoxLayout::new(layout_size); + let used = layout_size.switch(dirs); - // And then, include this layout's main-axis extent. - main_extent += layout.size.get(dirs.main.axis()); - } + let children = std::mem::take(&mut self.space.layouts); + for (i, (boxed, aligns)) in children.into_iter().enumerate() { + let size = boxed.size.switch(dirs); + + let before = sums[i]; + let after = sum - sums[i + 1]; + let main_len = used.main - size.main; + let main_range = if dirs.main.is_positive() { + before .. main_len - after + } else { + main_len - before .. after + }; - // ------------------------------------------------------------------ // - // Step 4: Align each layout in its bounding box and collect everything - // into a single finished layout. + let cross_len = used.cross - size.cross; + let cross_range = if dirs.cross.is_positive() { + Length::ZERO .. cross_len + } else { + cross_len .. Length::ZERO + }; - let children = std::mem::take(&mut self.space.layouts); - for ((child, aligns), bound) in children.into_iter().zip(bounds) { - // Align the child in its own bounds. - let local = - bound.size().anchor(dirs, aligns) - child.size.anchor(dirs, aligns); + let main = aligns.main.apply(main_range); + let cross = aligns.cross.apply(cross_range); + let pos = Gen::new(main, cross).switch(dirs).to_point(); - // Make the local position in the bounds global. - let pos = bound.origin() + local; - layout.push_layout(pos, child); + layout.push_layout(pos, boxed); } self.layouts.push(layout); @@ -503,7 +479,7 @@ pub(super) struct Space { /// Whether to include a layout for this space even if it would be empty. hard: bool, /// The so-far accumulated layouts. - layouts: Vec<(BoxLayout, Gen2<GenAlign>)>, + layouts: Vec<(BoxLayout, Gen<Align>)>, /// The full size of this space. size: Size, /// The used size of this space. @@ -511,7 +487,7 @@ pub(super) struct Space { /// The remaining space. usable: Size, /// Which alignments for new boxes are still allowed. - pub(super) allowed_align: GenAlign, + pub(super) allowed_align: Align, } impl Space { @@ -523,7 +499,7 @@ impl Space { size, used: Size::ZERO, usable: size, - allowed_align: GenAlign::Start, + allowed_align: Align::Start, } } } diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs deleted file mode 100644 index 30bd9363..00000000 --- a/src/layout/primitive.rs +++ /dev/null @@ -1,510 +0,0 @@ -//! Layouting primitives. - -use std::fmt::{self, Display, Formatter}; -use std::ops::Range; - -use crate::geom::{Insets, Linear, Point, Size, Vec2}; - -/// Generic access to a structure's components. -pub trait Get<Index> { - /// The structure's component type. - type Component; - - /// Return the component for the specified index. - fn get(self, index: Index) -> Self::Component; - - /// Borrow the component for the specified index mutably. - fn get_mut(&mut self, index: Index) -> &mut Self::Component; -} - -/// Switch between the specific and generic representations of a type. -/// -/// The generic representation deals with main and cross axes while the specific -/// representation deals with horizontal and vertical axes. -pub trait Switch { - /// The type of the other version. - type Other; - - /// The other version of this type based on the current directions. - fn switch(self, dirs: Gen2<Dir>) -> Self::Other; -} - -/// The four directions into which content can be laid out. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Dir { - /// Left to right. - LTR, - /// Right to left. - RTL, - /// Top to bottom. - TTB, - /// Bottom to top. - BTT, -} - -impl Dir { - /// The specific axis this direction belongs to. - pub fn axis(self) -> SpecAxis { - match self { - Self::LTR | Self::RTL => SpecAxis::Horizontal, - Self::TTB | Self::BTT => SpecAxis::Vertical, - } - } - - /// The side this direction starts at. - pub fn start(self) -> Side { - match self { - Self::LTR => Side::Left, - Self::RTL => Side::Right, - Self::TTB => Side::Top, - Self::BTT => Side::Bottom, - } - } - - /// The side this direction ends at. - pub fn end(self) -> Side { - match self { - Self::LTR => Side::Right, - Self::RTL => Side::Left, - Self::TTB => Side::Bottom, - Self::BTT => Side::Top, - } - } - - /// Whether this direction points into the positive coordinate direction. - /// - /// The positive directions are left-to-right and top-to-bottom. - pub fn is_positive(self) -> bool { - match self { - Self::LTR | Self::TTB => true, - Self::RTL | Self::BTT => false, - } - } - - /// The factor for this direction. - /// - /// - `1.0` if the direction is positive. - /// - `-1.0` if the direction is negative. - pub fn factor(self) -> f64 { - if self.is_positive() { 1.0 } else { -1.0 } - } - - /// The inverse direction. - pub fn inv(self) -> Self { - match self { - Self::LTR => Self::RTL, - Self::RTL => Self::LTR, - Self::TTB => Self::BTT, - Self::BTT => Self::TTB, - } - } -} - -impl Display for Dir { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::LTR => "ltr", - Self::RTL => "rtl", - Self::TTB => "ttb", - Self::BTT => "btt", - }) - } -} - -/// A generic container with two components for the two generic axes. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] -pub struct Gen2<T> { - /// The main component. - pub main: T, - /// The cross component. - pub cross: T, -} - -impl<T> Gen2<T> { - /// Create a new instance from the two components. - pub fn new(main: T, cross: T) -> Self { - Self { main, cross } - } -} - -impl Gen2<f64> { - /// The instance that has both components set to zero. - pub const ZERO: Self = Self { main: 0.0, cross: 0.0 }; -} - -impl<T> Get<GenAxis> for Gen2<T> { - type Component = T; - - fn get(self, axis: GenAxis) -> T { - match axis { - GenAxis::Main => self.main, - GenAxis::Cross => self.cross, - } - } - - fn get_mut(&mut self, axis: GenAxis) -> &mut T { - match axis { - GenAxis::Main => &mut self.main, - GenAxis::Cross => &mut self.cross, - } - } -} - -impl<T> Switch for Gen2<T> { - type Other = Spec2<T>; - - fn switch(self, dirs: Gen2<Dir>) -> Self::Other { - match dirs.main.axis() { - SpecAxis::Horizontal => Spec2::new(self.main, self.cross), - SpecAxis::Vertical => Spec2::new(self.cross, self.main), - } - } -} - -/// A generic container with two components for the two specific axes. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] -pub struct Spec2<T> { - /// The horizontal component. - pub horizontal: T, - /// The vertical component. - pub vertical: T, -} - -impl<T> Spec2<T> { - /// Create a new instance from the two components. - pub fn new(horizontal: T, vertical: T) -> Self { - Self { horizontal, vertical } - } -} - -impl Spec2<f64> { - /// The instance that has both components set to zero. - pub const ZERO: Self = Self { horizontal: 0.0, vertical: 0.0 }; - - /// Convert to a 2D vector. - pub fn to_vec2(self) -> Vec2 { - Vec2::new(self.horizontal, self.vertical) - } - - /// Convert to a point. - pub fn to_point(self) -> Point { - Point::new(self.horizontal, self.vertical) - } - - /// Convert to a size. - pub fn to_size(self) -> Size { - Size::new(self.horizontal, self.vertical) - } -} - -impl<T> Get<SpecAxis> for Spec2<T> { - type Component = T; - - fn get(self, axis: SpecAxis) -> T { - match axis { - SpecAxis::Horizontal => self.horizontal, - SpecAxis::Vertical => self.vertical, - } - } - - fn get_mut(&mut self, axis: SpecAxis) -> &mut T { - match axis { - SpecAxis::Horizontal => &mut self.horizontal, - SpecAxis::Vertical => &mut self.vertical, - } - } -} - -impl<T> Switch for Spec2<T> { - type Other = Gen2<T>; - - fn switch(self, dirs: Gen2<Dir>) -> Self::Other { - match dirs.main.axis() { - SpecAxis::Horizontal => Gen2::new(self.horizontal, self.vertical), - SpecAxis::Vertical => Gen2::new(self.vertical, self.horizontal), - } - } -} - -/// The two generic layouting axes. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum GenAxis { - /// The axis pages and paragraphs are set along. - Main, - /// The axis words and lines are set along. - Cross, -} - -impl GenAxis { - /// The other axis. - pub fn other(self) -> Self { - match self { - Self::Main => Self::Cross, - Self::Cross => Self::Main, - } - } -} - -impl Switch for GenAxis { - type Other = SpecAxis; - - fn switch(self, dirs: Gen2<Dir>) -> Self::Other { - match self { - Self::Main => dirs.main.axis(), - Self::Cross => dirs.cross.axis(), - } - } -} - -impl Display for GenAxis { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Main => "main", - Self::Cross => "cross", - }) - } -} - -/// The two specific layouting axes. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum SpecAxis { - /// The vertical layouting axis. - Vertical, - /// The horizontal layouting axis. - Horizontal, -} - -impl SpecAxis { - /// The other axis. - pub fn other(self) -> Self { - match self { - Self::Horizontal => Self::Vertical, - Self::Vertical => Self::Horizontal, - } - } -} - -impl Switch for SpecAxis { - type Other = GenAxis; - - fn switch(self, dirs: Gen2<Dir>) -> Self::Other { - if self == dirs.main.axis() { - GenAxis::Main - } else { - debug_assert_eq!(self, dirs.cross.axis()); - GenAxis::Cross - } - } -} - -impl Display for SpecAxis { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Vertical => "vertical", - Self::Horizontal => "horizontal", - }) - } -} - -/// Where to align content along an axis in a generic context. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum GenAlign { - Start, - Center, - End, -} - -impl GenAlign { - /// Returns the position of this alignment in the given length. - pub fn apply(self, range: Range<f64>) -> f64 { - match self { - Self::Start => range.start, - Self::Center => (range.start + range.end) / 2.0, - Self::End => range.end, - } - } - - /// The inverse alignment. - pub fn inv(self) -> Self { - match self { - Self::Start => Self::End, - Self::Center => Self::Center, - Self::End => Self::Start, - } - } -} - -impl Default for GenAlign { - fn default() -> Self { - Self::Start - } -} - -impl Display for GenAlign { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Start => "start", - Self::Center => "center", - Self::End => "end", - }) - } -} - -/// Where to align content along an axis in a specific context. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum SpecAlign { - Left, - Right, - Top, - Bottom, - Center, -} - -impl SpecAlign { - /// The specific axis this alignment refers to. - /// - /// Returns `None` if this is `Center` since the axis is unknown. - pub fn axis(self) -> Option<SpecAxis> { - match self { - Self::Left => Some(SpecAxis::Horizontal), - Self::Right => Some(SpecAxis::Horizontal), - Self::Top => Some(SpecAxis::Vertical), - Self::Bottom => Some(SpecAxis::Vertical), - Self::Center => None, - } - } - - /// The inverse alignment. - pub fn inv(self) -> Self { - match self { - Self::Left => Self::Right, - Self::Right => Self::Left, - Self::Top => Self::Bottom, - Self::Bottom => Self::Top, - Self::Center => Self::Center, - } - } -} - -impl Switch for SpecAlign { - type Other = GenAlign; - - fn switch(self, dirs: Gen2<Dir>) -> Self::Other { - let get = |dir: Dir, at_positive_start| { - if dir.is_positive() == at_positive_start { - GenAlign::Start - } else { - GenAlign::End - } - }; - - let dirs = dirs.switch(dirs); - match self { - Self::Left => get(dirs.horizontal, true), - Self::Right => get(dirs.horizontal, false), - Self::Top => get(dirs.vertical, true), - Self::Bottom => get(dirs.vertical, false), - Self::Center => GenAlign::Center, - } - } -} - -impl Display for SpecAlign { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Self::Left => "left", - Self::Right => "right", - Self::Top => "top", - Self::Bottom => "bottom", - Self::Center => "center", - }) - } -} - -/// A generic container with left, top, right and bottom components. -#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] -pub struct Sides<T> { - /// The value for the left side. - pub left: T, - /// The value for the top side. - pub top: T, - /// The value for the right side. - pub right: T, - /// The value for the bottom side. - pub bottom: T, -} - -impl<T> Sides<T> { - /// Create a new box from four sizes. - pub fn new(left: T, top: T, right: T, bottom: T) -> Self { - Self { left, top, right, bottom } - } - - /// Create an instance with all four components set to the same `value`. - pub fn uniform(value: T) -> Self - where - T: Clone, - { - Self { - left: value.clone(), - top: value.clone(), - right: value.clone(), - bottom: value, - } - } -} - -impl Sides<Linear> { - /// The absolute insets. - pub fn insets(self, Size { width, height }: Size) -> Insets { - Insets { - x0: -self.left.eval(width), - y0: -self.top.eval(height), - x1: -self.right.eval(width), - y1: -self.bottom.eval(height), - } - } -} - -impl<T> Get<Side> for Sides<T> { - type Component = T; - - fn get(self, side: Side) -> T { - match side { - Side::Left => self.left, - Side::Top => self.top, - Side::Right => self.right, - Side::Bottom => self.bottom, - } - } - - fn get_mut(&mut self, side: Side) -> &mut T { - match side { - Side::Left => &mut self.left, - Side::Top => &mut self.top, - Side::Right => &mut self.right, - Side::Bottom => &mut self.bottom, - } - } -} - -/// A side of a container. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Side { - Left, - Top, - Right, - Bottom, -} - -impl Side { - /// The opposite side. - pub fn inv(self) -> Self { - match self { - Self::Left => Self::Right, - Self::Top => Self::Bottom, - Self::Right => Self::Left, - Self::Bottom => Self::Top, - } - } -} diff --git a/src/layout/nodes/spacing.rs b/src/layout/spacing.rs index 9d72f7ca..9eac1ad5 100644 --- a/src/layout/nodes/spacing.rs +++ b/src/layout/spacing.rs @@ -5,7 +5,7 @@ use super::*; /// A node that inserts spacing. #[derive(Copy, Clone, PartialEq)] pub struct Spacing { - pub amount: f64, + pub amount: Length, pub softness: Softness, } diff --git a/src/layout/nodes/stack.rs b/src/layout/stack.rs index cca64e62..6cbe03e3 100644 --- a/src/layout/nodes/stack.rs +++ b/src/layout/stack.rs @@ -24,10 +24,10 @@ use super::*; /// sentence in the second box. #[derive(Debug, Clone, PartialEq)] pub struct Stack { - pub dirs: Gen2<Dir>, + pub dirs: Gen<Dir>, pub children: Vec<LayoutNode>, - pub aligns: Gen2<GenAlign>, - pub expand: Spec2<bool>, + pub aligns: Gen<Align>, + pub expand: Spec<bool>, } #[async_trait(?Send)] @@ -90,17 +90,17 @@ impl Layout for Stack { } struct StackSpace { - dirs: Gen2<Dir>, - expand: Spec2<bool>, - boxes: Vec<(BoxLayout, Gen2<GenAlign>)>, + dirs: Gen<Dir>, + expand: Spec<bool>, + boxes: Vec<(BoxLayout, Gen<Align>)>, full_size: Size, usable: Size, used: Size, - ruler: GenAlign, + ruler: Align, } impl StackSpace { - fn new(dirs: Gen2<Dir>, expand: Spec2<bool>, size: Size) -> Self { + fn new(dirs: Gen<Dir>, expand: Spec<bool>, size: Size) -> Self { Self { dirs, expand, @@ -108,14 +108,14 @@ impl StackSpace { full_size: size, usable: size, used: Size::ZERO, - ruler: GenAlign::Start, + ruler: Align::Start, } } fn push_box( &mut self, boxed: BoxLayout, - aligns: Gen2<GenAlign>, + aligns: Gen<Align>, ) -> Result<(), BoxLayout> { let main = self.dirs.main.axis(); let cross = self.dirs.cross.axis(); @@ -133,15 +133,15 @@ impl StackSpace { Ok(()) } - fn push_spacing(&mut self, spacing: f64) { + fn push_spacing(&mut self, spacing: Length) { let main = self.dirs.main.axis(); let max = self.usable.get(main); let trimmed = spacing.min(max); *self.used.get_mut(main) += trimmed; *self.usable.get_mut(main) -= trimmed; - let size = Gen2::new(trimmed, 0.0).switch(self.dirs); - self.boxes.push((BoxLayout::new(size.to_size()), Gen2::default())); + let size = Gen::new(trimmed, Length::ZERO).switch(self.dirs); + self.boxes.push((BoxLayout::new(size.to_size()), Gen::default())); } fn finish(mut self) -> BoxLayout { @@ -156,7 +156,7 @@ impl StackSpace { self.used.height = self.full_size.height; } - let mut sum = 0.0; + let mut sum = Length::ZERO; let mut sums = Vec::with_capacity(self.boxes.len() + 1); for (boxed, _) in &self.boxes { @@ -183,14 +183,14 @@ impl StackSpace { let cross_len = used.cross - size.cross; let cross_range = if dirs.cross.is_positive() { - 0.0 .. cross_len + Length::ZERO .. cross_len } else { - cross_len .. 0.0 + cross_len .. Length::ZERO }; let main = aligns.main.apply(main_range); let cross = aligns.cross.apply(cross_range); - let pos = Gen2::new(main, cross).switch(dirs).to_point(); + let pos = Gen::new(main, cross).switch(dirs).to_point(); layout.push_layout(pos, boxed); } diff --git a/src/layout/nodes/text.rs b/src/layout/text.rs index b0c4a458..fafc1b14 100644 --- a/src/layout/nodes/text.rs +++ b/src/layout/text.rs @@ -10,11 +10,11 @@ use crate::shaping; #[derive(Clone, PartialEq)] pub struct Text { pub text: String, - pub size: f64, + pub size: Length, pub dir: Dir, pub fallback: Rc<FallbackTree>, pub variant: FontVariant, - pub aligns: Gen2<GenAlign>, + pub aligns: Gen<Align>, } #[async_trait(?Send)] |
