summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-10 22:19:36 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-10 22:19:36 +0200
commit92c01da36016e94ff20163806ddcbcf7e33d4031 (patch)
tree1a900b3c11edcc93e9153fada3ce92310db5768b /src/layout
parent42500d5ed85539c5ab04dd3544beaf802da29be9 (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.rs29
-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.rs510
-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)]