summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-06 13:13:18 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-06 13:13:18 +0200
commitc6a6870978226f2c6e3b258a6270cc0dcde58c72 (patch)
treee3e75fad9055c6af5f747026e7c0146b4d035d09 /src/layout
parent5a7a32a9bafbcc69077e7766451310ab5ece62bf (diff)
Rename secondary/primary to main/cross ✏
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/line.rs80
-rw-r--r--src/layout/mod.rs18
-rw-r--r--src/layout/primitive.rs380
-rw-r--r--src/layout/stack.rs120
-rw-r--r--src/layout/tree.rs29
5 files changed, 337 insertions, 290 deletions
diff --git a/src/layout/line.rs b/src/layout/line.rs
index 745a0d14..acf143c0 100644
--- a/src/layout/line.rs
+++ b/src/layout/line.rs
@@ -1,9 +1,8 @@
//! Arranging boxes into lines.
//!
-//! Along the primary axis, the boxes are laid out next to each other as long as
-//! they fit into a line. When necessary, a line break is inserted and the new
-//! line is offset along the secondary axis by the height of the previous line
-//! plus extra line spacing.
+//! The boxes are laid out along the cross axis as long as they fit into a line.
+//! When necessary, a line break is inserted and the new line is offset along
+//! the main axis by the height of the previous line plus extra line spacing.
//!
//! Internally, the line layouter uses a stack layouter to stack the finished
//! lines on top of each.
@@ -23,8 +22,8 @@ pub struct LineLayouter {
/// The context for line layouting.
#[derive(Debug, Clone)]
pub struct LineContext {
- /// The initial layouting system, which can be updated through `set_sys`.
- pub sys: LayoutSystem,
+ /// The layout directions.
+ pub dirs: Gen2<Dir>,
/// The spaces to layout into.
pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
@@ -40,7 +39,7 @@ impl LineLayouter {
Self {
stack: StackLayouter::new(StackContext {
spaces: ctx.spaces.clone(),
- sys: ctx.sys,
+ dirs: ctx.dirs,
repeat: ctx.repeat,
}),
ctx,
@@ -49,26 +48,24 @@ impl LineLayouter {
}
/// Add a layout.
- pub fn add(&mut self, layout: BoxLayout, align: LayoutAlign) {
- let sys = self.ctx.sys;
-
- if let Some(prev) = self.run.align {
- if align.secondary != prev.secondary {
+ pub fn add(&mut self, layout: BoxLayout, aligns: Gen2<GenAlign>) {
+ if let Some(prev) = self.run.aligns {
+ if aligns.main != prev.main {
// TODO: Issue warning for non-fitting alignment in
// non-repeating context.
- let fitting = self.stack.is_fitting_alignment(align);
+ let fitting = self.stack.is_fitting_alignment(aligns);
if !fitting && self.ctx.repeat {
self.finish_space(true);
} else {
self.finish_line();
}
- } else if align.primary < prev.primary {
+ } else if aligns.cross < prev.cross {
self.finish_line();
- } else if align.primary > prev.primary {
+ } else if aligns.cross > prev.cross {
let mut rest_run = LineRun::new();
- let usable = self.stack.usable().get(sys.primary.axis());
- rest_run.usable = Some(match align.primary {
+ let usable = self.stack.usable().get(self.ctx.dirs.cross.axis());
+ rest_run.usable = Some(match aligns.cross {
GenAlign::Start => unreachable!("start > x"),
GenAlign::Center => usable - 2.0 * self.run.size.width,
GenAlign::End => usable - self.run.size.width,
@@ -84,10 +81,10 @@ impl LineLayouter {
}
if let LastSpacing::Soft(spacing, _) = self.run.last_spacing {
- self.add_primary_spacing(spacing, SpacingKind::Hard);
+ self.add_cross_spacing(spacing, SpacingKind::Hard);
}
- let size = layout.size.generalized(sys);
+ let size = layout.size.generalized(self.ctx.dirs);
if !self.usable().fits(size) {
if !self.line_is_empty() {
@@ -100,7 +97,7 @@ impl LineLayouter {
}
}
- self.run.align = Some(align);
+ self.run.aligns = Some(aligns);
self.run.layouts.push((self.run.size.width, layout));
self.run.size.width += size.width;
@@ -114,19 +111,25 @@ impl LineLayouter {
/// needed.
fn usable(&self) -> Size {
// The base is the usable space of the stack layouter.
- let mut usable = self.stack.usable().generalized(self.ctx.sys);
+ let mut usable = self.stack.usable().generalized(self.ctx.dirs);
// If there was another run already, override the stack's size.
- if let Some(primary) = self.run.usable {
- usable.width = primary;
+ if let Some(cross) = self.run.usable {
+ usable.width = cross;
}
usable.width -= self.run.size.width;
usable
}
+ /// Finish the line and add spacing to the underlying stack.
+ pub fn add_main_spacing(&mut self, spacing: f64, kind: SpacingKind) {
+ self.finish_line_if_not_empty();
+ self.stack.add_spacing(spacing, kind)
+ }
+
/// Add spacing to the line.
- pub fn add_primary_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
+ pub fn add_cross_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
match kind {
SpacingKind::Hard => {
spacing = spacing.min(self.usable().width);
@@ -150,19 +153,6 @@ impl LineLayouter {
}
}
- /// Finish the line and add spacing to the underlying stack.
- pub fn add_secondary_spacing(&mut self, spacing: f64, kind: SpacingKind) {
- self.finish_line_if_not_empty();
- self.stack.add_spacing(spacing, kind)
- }
-
- /// Update the layouting system.
- pub fn set_sys(&mut self, sys: LayoutSystem) {
- self.finish_line_if_not_empty();
- self.ctx.sys = sys;
- self.stack.set_sys(sys)
- }
-
/// Update the layouting spaces.
///
/// If `replace_empty` is true, the current space is replaced if there are
@@ -181,7 +171,7 @@ impl LineLayouter {
/// it will fit into this layouter's underlying stack.
pub fn remaining(&self) -> Vec<LayoutSpace> {
let mut spaces = self.stack.remaining();
- *spaces[0].size.get_mut(self.ctx.sys.secondary.axis()) -= self.run.size.height;
+ *spaces[0].size.get_mut(self.ctx.dirs.main.axis()) -= self.run.size.height;
spaces
}
@@ -206,17 +196,17 @@ impl LineLayouter {
/// Finish the active line and start a new one.
pub fn finish_line(&mut self) {
- let mut layout = BoxLayout::new(self.run.size.specialized(self.ctx.sys));
- let align = self.run.align.unwrap_or_default();
+ let mut layout = BoxLayout::new(self.run.size.specialized(self.ctx.dirs));
+ let aligns = self.run.aligns.unwrap_or_default();
let layouts = std::mem::take(&mut self.run.layouts);
for (offset, child) in layouts {
- let x = match self.ctx.sys.primary.is_positive() {
+ let x = match self.ctx.dirs.cross.is_positive() {
true => offset,
false => {
self.run.size.width
- offset
- - child.size.get(self.ctx.sys.primary.axis())
+ - child.size.get(self.ctx.dirs.cross.axis())
}
};
@@ -224,7 +214,7 @@ impl LineLayouter {
layout.push_layout(pos, child);
}
- self.stack.add(layout, align);
+ self.stack.add(layout, aligns);
self.run = LineRun::new();
self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE);
@@ -249,7 +239,7 @@ struct LineRun {
/// 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.
- align: Option<LayoutAlign>,
+ aligns: Option<Gen2<GenAlign>>,
/// The amount of space left by another run on the same line or `None` if
/// this is the only run so far.
usable: Option<f64>,
@@ -263,7 +253,7 @@ impl LineRun {
Self {
layouts: vec![],
size: Size::ZERO,
- align: None,
+ aligns: None,
usable: None,
last_spacing: LastSpacing::Hard,
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 2ba1b0de..f9372e50 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -11,11 +11,10 @@ pub use primitive::*;
pub use stack::*;
pub use tree::*;
-use crate::geom::{Insets, Point, Rect, RectExt, Size, SizeExt};
-
use crate::diag::Diag;
use crate::eval::{PageState, State, TextState};
use crate::font::SharedFontLoader;
+use crate::geom::{Insets, Point, Rect, RectExt, Size, SizeExt};
use crate::shaping::Shaped;
use crate::syntax::{Deco, Spanned, SynTree};
use crate::{Feedback, Pass};
@@ -29,7 +28,7 @@ pub async fn layout(
let space = LayoutSpace {
size: state.page.size,
insets: state.page.insets(),
- expansion: LayoutExpansion::new(true, true),
+ expansion: Spec2::new(true, true),
};
let constraints = LayoutConstraints {
@@ -134,7 +133,7 @@ pub struct LayoutSpace {
pub insets: Insets,
/// 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 expansion: LayoutExpansion,
+ pub expansion: Spec2<bool>,
}
impl LayoutSpace {
@@ -154,7 +153,7 @@ impl LayoutSpace {
Self {
size: self.usable(),
insets: Insets::ZERO,
- expansion: LayoutExpansion::new(false, false),
+ expansion: Spec2::new(false, false),
}
}
}
@@ -172,8 +171,8 @@ pub enum Command {
LayoutSyntaxTree(SynTree),
/// Add a finished layout.
- Add(BoxLayout, LayoutAlign),
- /// Add spacing of the given kind along the primary or secondary axis. The
+ Add(BoxLayout, Gen2<GenAlign>),
+ /// Add spacing of the given kind along the given axis. The
/// kind defines how the spacing interacts with surrounding spacing.
AddSpacing(f64, SpacingKind, GenAxis),
@@ -187,11 +186,8 @@ pub enum Command {
SetTextState(TextState),
/// Update the page style.
SetPageState(PageState),
- /// Update the layouting system along which future boxes will be laid
- /// out. This ends the current line.
- SetSystem(LayoutSystem),
/// Update the alignment for future boxes added to this layouting process.
- SetAlignment(LayoutAlign),
+ SetAlignment(Gen2<GenAlign>),
}
/// Defines how spacing interacts with surrounding spacing.
diff --git a/src/layout/primitive.rs b/src/layout/primitive.rs
index 64cd1dff..9070c972 100644
--- a/src/layout/primitive.rs
+++ b/src/layout/primitive.rs
@@ -2,30 +2,6 @@
use std::fmt::{self, Display, Formatter};
-/// Specifies the directions into which content is laid out.
-///
-/// The primary component defines into which direction text and lines flow and the
-/// secondary into which paragraphs and pages grow.
-pub type LayoutSystem = Gen2<Dir>;
-
-impl Default for LayoutSystem {
- fn default() -> Self {
- Self::new(Dir::LTR, Dir::TTB)
- }
-}
-
-/// Specifies where to align a layout in a parent container.
-pub type LayoutAlign = Gen2<GenAlign>;
-
-impl Default for LayoutAlign {
- fn default() -> Self {
- Self::new(GenAlign::Start, GenAlign::Start)
- }
-}
-
-/// Whether to expand a layout to an area's full size or shrink it to fit its content.
-pub type LayoutExpansion = Spec2<bool>;
-
/// The four directions into which content can be laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Dir {
@@ -66,25 +42,30 @@ impl Dir {
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,
- }
- }
-
/// The side of this direction the alignment identifies.
///
/// `Center` alignment is treated the same as `Start` alignment.
pub fn side(self, align: GenAlign) -> Side {
- match if align == GenAlign::End { self.inv() } else { self } {
+ let start = match self {
Self::LTR => Side::Left,
Self::RTL => Side::Right,
Self::TTB => Side::Top,
Self::BTT => Side::Bottom,
+ };
+
+ match align {
+ GenAlign::Start | GenAlign::Center => start,
+ GenAlign::End => start.inv(),
+ }
+ }
+
+ /// 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,
}
}
}
@@ -100,27 +81,159 @@ impl Display for Dir {
}
}
+/// Convert a type into its generic representation.
+///
+/// The generic representation deals with main and cross axes while the specific
+/// representation deals with horizontal and vertical axes.
+///
+/// See also [`ToSpec`] for the inverse conversion.
+///
+/// [`ToSpec`]: trait.ToSpec.html
+pub trait ToGen {
+ /// The generic version of this type.
+ type Output;
+
+ /// The generic version of this type based on the current directions.
+ fn to_gen(self, dirs: Gen2<Dir>) -> Self::Output;
+}
+
+/// Convert a type into its specific representation.
+///
+/// The specific representation deals with horizontal and vertical axes while
+/// the generic representation deals with main and cross axes.
+///
+/// See also [`ToGen`] for the inverse conversion.
+///
+/// [`ToGen`]: trait.ToGen.html
+pub trait ToSpec {
+ /// The specific version of this type.
+ type Output;
+
+ /// The specific version of this type based on the current directions.
+ fn to_spec(self, dirs: Gen2<Dir>) -> Self::Output;
+}
+
+/// 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 }
+ }
+
+ /// Return the component for the specified generic axis.
+ pub fn get(self, axis: GenAxis) -> T {
+ match axis {
+ GenAxis::Main => self.main,
+ GenAxis::Cross => self.cross,
+ }
+ }
+
+ /// Borrow the component for the specified generic axis mutably.
+ pub fn get_mut(&mut self, axis: GenAxis) -> &mut T {
+ match axis {
+ GenAxis::Main => &mut self.main,
+ GenAxis::Cross => &mut self.cross,
+ }
+ }
+}
+
+impl<T> ToSpec for Gen2<T> {
+ type Output = Spec2<T>;
+
+ fn to_spec(self, dirs: Gen2<Dir>) -> Self::Output {
+ 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 }
+ }
+
+ /// Return the component for the given specific axis.
+ pub fn get(self, axis: SpecAxis) -> T {
+ match axis {
+ SpecAxis::Horizontal => self.horizontal,
+ SpecAxis::Vertical => self.vertical,
+ }
+ }
+
+ /// Borrow the component for the given specific axis mutably.
+ pub fn get_mut(&mut self, axis: SpecAxis) -> &mut T {
+ match axis {
+ SpecAxis::Horizontal => &mut self.horizontal,
+ SpecAxis::Vertical => &mut self.vertical,
+ }
+ }
+}
+
+impl<T> ToGen for Spec2<T> {
+ type Output = Gen2<T>;
+
+ fn to_gen(self, dirs: Gen2<Dir>) -> Self::Output {
+ 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 primary layouting direction into which text and lines flow.
- Primary,
- /// The secondary layouting direction into which paragraphs grow.
- Secondary,
+ /// The axis pages and paragraphs are set along.
+ Main,
+ /// The axis words and lines are set along.
+ Cross,
}
impl GenAxis {
- /// The specific version of this axis in the given layout system.
- pub fn to_spec(self, sys: LayoutSystem) -> SpecAxis {
- sys.get(self).axis()
+ /// The other axis.
+ pub fn other(self) -> Self {
+ match self {
+ Self::Main => Self::Cross,
+ Self::Cross => Self::Main,
+ }
+ }
+}
+
+impl ToSpec for GenAxis {
+ type Output = SpecAxis;
+
+ fn to_spec(self, dirs: Gen2<Dir>) -> Self::Output {
+ 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::Primary => "primary",
- Self::Secondary => "secondary",
+ Self::Main => "main",
+ Self::Cross => "cross",
})
}
}
@@ -128,19 +241,31 @@ impl Display for GenAxis {
/// The two specific layouting axes.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SpecAxis {
- /// The horizontal layouting axis.
- Horizontal,
/// The vertical layouting axis.
Vertical,
+ /// The horizontal layouting axis.
+ Horizontal,
}
impl SpecAxis {
- /// The generic version of this axis in the given layout system.
- pub fn to_gen(self, sys: LayoutSystem) -> GenAxis {
- if self == sys.primary.axis() {
- GenAxis::Primary
+ /// The other axis.
+ pub fn other(self) -> Self {
+ match self {
+ Self::Horizontal => Self::Vertical,
+ Self::Vertical => Self::Horizontal,
+ }
+ }
+}
+
+impl ToGen for SpecAxis {
+ type Output = GenAxis;
+
+ fn to_gen(self, dirs: Gen2<Dir>) -> Self::Output {
+ if self == dirs.main.axis() {
+ GenAxis::Main
} else {
- GenAxis::Secondary
+ debug_assert_eq!(self, dirs.cross.axis());
+ GenAxis::Cross
}
}
}
@@ -148,8 +273,8 @@ impl SpecAxis {
impl Display for SpecAxis {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(match self {
- Self::Horizontal => "horizontal",
Self::Vertical => "vertical",
+ Self::Horizontal => "horizontal",
})
}
}
@@ -173,6 +298,12 @@ impl GenAlign {
}
}
+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 {
@@ -207,21 +338,36 @@ impl SpecAlign {
}
}
- /// The generic version of this alignment in the given layout system.
- pub fn to_gen(self, sys: LayoutSystem) -> GenAlign {
- let get = |spec: SpecAxis, positive: GenAlign| {
- if sys.get(spec.to_gen(sys)).is_positive() {
- positive
+ /// 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 ToGen for SpecAlign {
+ type Output = GenAlign;
+
+ fn to_gen(self, dirs: Gen2<Dir>) -> Self::Output {
+ let dirs = dirs.to_spec(dirs);
+ let get = |dir: Dir, at_positive_start| {
+ if dir.is_positive() == at_positive_start {
+ GenAlign::Start
} else {
- positive.inv()
+ GenAlign::End
}
};
match self {
- Self::Left => get(SpecAxis::Horizontal, GenAlign::Start),
- Self::Right => get(SpecAxis::Horizontal, GenAlign::End),
- Self::Top => get(SpecAxis::Vertical, GenAlign::Start),
- Self::Bottom => get(SpecAxis::Vertical, GenAlign::End),
+ 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,
}
}
@@ -239,91 +385,6 @@ impl Display for SpecAlign {
}
}
-/// 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,
- }
- }
-}
-
-/// A generic container with two components for the two generic axes.
-#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
-pub struct Gen2<T> {
- /// The primary component.
- pub primary: T,
- /// The secondary component.
- pub secondary: T,
-}
-
-impl<T> Gen2<T> {
- /// Create a new instance from the two components.
- pub fn new(primary: T, secondary: T) -> Self {
- Self { primary, secondary }
- }
-
- /// Return the component for the specified generic axis.
- pub fn get(self, axis: GenAxis) -> T {
- match axis {
- GenAxis::Primary => self.primary,
- GenAxis::Secondary => self.secondary,
- }
- }
-
- /// Borrow the component for the specified generic axis mutably.
- pub fn get_mut(&mut self, axis: GenAxis) -> &mut T {
- match axis {
- GenAxis::Primary => &mut self.primary,
- GenAxis::Secondary => &mut self.secondary,
- }
- }
-}
-
-/// 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 }
- }
-
- /// Return the component for the given specific axis.
- pub fn get(self, axis: SpecAxis) -> T {
- match axis {
- SpecAxis::Horizontal => self.horizontal,
- SpecAxis::Vertical => self.vertical,
- }
- }
-
- /// Borrow the component for the given specific axis mutably.
- pub fn get_mut(&mut self, axis: SpecAxis) -> &mut T {
- match axis {
- SpecAxis::Horizontal => &mut self.horizontal,
- SpecAxis::Vertical => &mut self.vertical,
- }
- }
-}
-
/// A generic container with left, top, right and bottom components.
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub struct Sides<T> {
@@ -360,8 +421,8 @@ impl<T> Sides<T> {
pub fn get(self, side: Side) -> T {
match side {
Side::Left => self.left,
- Side::Right => self.right,
Side::Top => self.top,
+ Side::Right => self.right,
Side::Bottom => self.bottom,
}
}
@@ -370,9 +431,30 @@ impl<T> Sides<T> {
pub fn get_mut(&mut self, side: Side) -> &mut T {
match side {
Side::Left => &mut self.left,
- Side::Right => &mut self.right,
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/stack.rs b/src/layout/stack.rs
index de933fbf..a98e4f52 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -1,4 +1,4 @@
-//! Arranging boxes into a stack along the secondary axis.
+//! Arranging boxes into a stack along the main axis.
//!
//! Individual layouts can be aligned at `Start`, `Center` or `End` along both
//! axes. These alignments are with respect to the size of the finished layout
@@ -34,8 +34,8 @@ pub struct StackLayouter {
/// The context for stack layouting.
#[derive(Debug, Clone)]
pub struct StackContext {
- /// The initial layouting system, which can be updated through `set_sys`.
- pub sys: LayoutSystem,
+ /// The layouting directions.
+ pub dirs: Gen2<Dir>,
/// The spaces to layout into.
pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
@@ -55,15 +55,15 @@ impl StackLayouter {
}
/// Add a layout to the stack.
- pub fn add(&mut self, layout: BoxLayout, align: LayoutAlign) {
+ pub fn add(&mut self, layout: BoxLayout, aligns: Gen2<GenAlign>) {
// If the alignment cannot be fitted in this space, finish it.
// TODO: Issue warning for non-fitting alignment in non-repeating
// context.
- if !self.update_rulers(align) && self.ctx.repeat {
+ if !self.update_rulers(aligns) && self.ctx.repeat {
self.finish_space(true);
}
- // Now, we add a possibly cached soft space. If the secondary alignment
+ // Now, we add a possibly cached soft space. If the main alignment
// changed before, a possibly cached space would have already been
// discarded.
if let LastSpacing::Soft(spacing, _) = self.space.last_spacing {
@@ -76,11 +76,11 @@ impl StackLayouter {
}
// Change the usable space and size of the space.
- self.update_metrics(layout.size.generalized(self.ctx.sys));
+ self.update_metrics(layout.size.generalized(self.ctx.dirs));
// Add the box to the vector and remember that spacings are allowed
// again.
- self.space.layouts.push((self.ctx.sys, align, layout));
+ self.space.layouts.push((self.ctx.dirs, aligns, layout));
self.space.last_spacing = LastSpacing::None;
}
@@ -90,15 +90,15 @@ impl StackLayouter {
// A hard space is simply an empty box.
SpacingKind::Hard => {
// Reduce the spacing such that it definitely fits.
- let axis = self.ctx.sys.secondary.axis();
+ let axis = self.ctx.dirs.main.axis();
spacing = spacing.min(self.space.usable.get(axis));
let size = Size::new(0.0, spacing);
self.update_metrics(size);
self.space.layouts.push((
- self.ctx.sys,
- LayoutAlign::default(),
- BoxLayout::new(size.specialized(self.ctx.sys)),
+ self.ctx.dirs,
+ Gen2::default(),
+ BoxLayout::new(size.specialized(self.ctx.dirs)),
));
self.space.last_spacing = LastSpacing::Hard;
@@ -121,37 +121,34 @@ impl StackLayouter {
}
fn update_metrics(&mut self, added: Size) {
- let sys = self.ctx.sys;
-
- let mut size = self.space.size.generalized(sys);
- let mut extra = self.space.extra.generalized(sys);
+ let mut size = self.space.size.generalized(self.ctx.dirs);
+ let mut extra = self.space.extra.generalized(self.ctx.dirs);
size.width += (added.width - extra.width).max(0.0);
size.height += (added.height - extra.height).max(0.0);
-
extra.width = extra.width.max(added.width);
extra.height = (extra.height - added.height).max(0.0);
- self.space.size = size.specialized(sys);
- self.space.extra = extra.specialized(sys);
- *self.space.usable.get_mut(sys.secondary.axis()) -= added.height;
+ self.space.size = size.specialized(self.ctx.dirs);
+ self.space.extra = extra.specialized(self.ctx.dirs);
+ *self.space.usable.get_mut(self.ctx.dirs.main.axis()) -= added.height;
}
/// Returns true if a space break is necessary.
- fn update_rulers(&mut self, align: LayoutAlign) -> bool {
- let allowed = self.is_fitting_alignment(align);
+ fn update_rulers(&mut self, aligns: Gen2<GenAlign>) -> bool {
+ let allowed = self.is_fitting_alignment(aligns);
if allowed {
- let side = self.ctx.sys.secondary.side(GenAlign::Start);
- *self.space.rulers.get_mut(side) = align.secondary;
+ let side = self.ctx.dirs.main.side(GenAlign::Start);
+ *self.space.rulers.get_mut(side) = aligns.main;
}
allowed
}
/// Whether a layout with the given alignment can still be layouted into the
/// active space or a space break is necessary.
- pub(crate) fn is_fitting_alignment(&self, align: LayoutAlign) -> bool {
- self.is_fitting_axis(self.ctx.sys.primary, align.primary)
- && self.is_fitting_axis(self.ctx.sys.secondary, align.secondary)
+ pub(crate) fn is_fitting_alignment(&self, aligns: Gen2<GenAlign>) -> bool {
+ self.is_fitting_axis(self.ctx.dirs.main, aligns.main)
+ && self.is_fitting_axis(self.ctx.dirs.cross, aligns.cross)
}
fn is_fitting_axis(&self, dir: Dir, align: GenAlign) -> bool {
@@ -159,16 +156,6 @@ impl StackLayouter {
&& align <= self.space.rulers.get(dir.side(GenAlign::End)).inv()
}
- /// Update the layouting system.
- pub fn set_sys(&mut self, sys: LayoutSystem) {
- // Forget the spacing because it is not relevant anymore.
- if sys.secondary != self.ctx.sys.secondary {
- self.space.last_spacing = LastSpacing::Hard;
- }
-
- self.ctx.sys = sys;
- }
-
/// Update the layouting spaces.
///
/// If `replace_empty` is true, the current space is replaced if there are
@@ -200,12 +187,10 @@ impl StackLayouter {
/// The remaining inner spaces. If something is laid out into these spaces,
/// it will fit into this stack.
pub fn remaining(&self) -> Vec<LayoutSpace> {
- let size = self.usable();
-
let mut spaces = vec![LayoutSpace {
- size,
+ size: self.usable(),
insets: Insets::ZERO,
- expansion: LayoutExpansion::new(false, false),
+ expansion: Spec2::new(false, false),
}];
for space in &self.ctx.spaces[self.next_space() ..] {
@@ -219,7 +204,7 @@ impl StackLayouter {
pub fn usable(&self) -> Size {
self.space.usable
- Size::new(0.0, self.space.last_spacing.soft_or_zero())
- .specialized(self.ctx.sys)
+ .specialized(self.ctx.dirs)
}
/// Whether the current layout space is empty.
@@ -274,7 +259,7 @@ impl StackLayouter {
y1: start.y + self.space.size.height,
};
- for (sys, _, layout) in &self.space.layouts {
+ for &(dirs, _, ref layout) in &self.space.layouts {
// First, we store the bounds calculated so far (which were reduced
// by the predecessors of this layout) as the initial bounding box
// of this layout.
@@ -283,41 +268,42 @@ impl StackLayouter {
// Then, we 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
- // extent along the secondary axis.
- *bound.get_mut(sys.secondary, GenAlign::Start) +=
- sys.secondary.factor() * layout.size.get(sys.secondary.axis());
+ // main-axis extent.
+ *bound.get_mut(dirs.main.side(GenAlign::Start)) +=
+ dirs.main.factor() * layout.size.get(dirs.main.axis());
}
// ------------------------------------------------------------------ //
// Step 3: Backward pass. Reduce the bounding boxes from the previous
// layouts by what is taken by the following ones.
- // The `x` field stores the maximal primary extent in one axis-aligned
- // run, while the `y` fields stores the accumulated secondary extent.
+ // The `x` field stores the maximal cross-axis extent in one
+ // axis-aligned run, while the `y` fields stores the accumulated
+ // main-axis extent.
let mut extent = Size::ZERO;
let mut rotation = SpecAxis::Vertical;
for (bound, entry) in bounds.iter_mut().zip(&self.space.layouts).rev() {
- let (sys, _, layout) = entry;
+ let &(dirs, _, ref layout) = entry;
- // When the axes are rotated, the maximal primary size (`extent.x`)
- // dictates how much secondary extent the whole run had. This value
- // is thus stored in `extent.y`. The primary extent is reset for
- // this new axis-aligned run.
- if rotation != sys.secondary.axis() {
+ // When the axes are rotated, the maximal cross-axis size
+ // (`extent.x`) dictates how much main-axis extent the whole run
+ // had. This value is thus stored in `extent.y`. The cross-axis
+ // extent is reset for this new axis-aligned run.
+ if rotation != dirs.main.axis() {
extent.height = extent.width;
extent.width = 0.0;
- rotation = sys.secondary.axis();
+ rotation = dirs.main.axis();
}
// We reduce the bounding box of this layout at its end by the
- // accumulated secondary extent of all layouts we have seen so far,
+ // accumulated main-axis extent of all layouts we have seen so far,
// which are the layouts after this one since we iterate reversed.
- *bound.get_mut(sys.secondary, GenAlign::End) -=
- sys.secondary.factor() * extent.height;
+ *bound.get_mut(dirs.main.side(GenAlign::End)) -=
+ dirs.main.factor() * extent.height;
- // Then, we add this layout's secondary extent to the accumulator.
- let size = layout.size.generalized(*sys);
+ // Then, we add this layout's main-axis extent to the accumulator.
+ let size = layout.size.generalized(dirs);
extent.width = extent.width.max(size.width);
extent.height += size.height;
}
@@ -329,14 +315,14 @@ impl StackLayouter {
let mut layout = BoxLayout::new(size);
let layouts = std::mem::take(&mut self.space.layouts);
- for ((sys, align, child), bound) in layouts.into_iter().zip(bounds) {
- let size = child.size.specialized(sys);
+ for ((dirs, aligns, child), bound) in layouts.into_iter().zip(bounds) {
+ let size = child.size.specialized(dirs);
// The space in which this layout is aligned is given by the
// distances between the borders of its bounding box.
- let usable = bound.size().generalized(sys);
- let local = usable.anchor(align, sys) - size.anchor(align, sys);
- let pos = bound.origin() + local.to_size().specialized(sys).to_vec2();
+ let usable = bound.size().generalized(dirs);
+ let local = usable.anchor(dirs, aligns) - size.anchor(dirs, aligns);
+ let pos = bound.origin() + local.to_size().specialized(dirs).to_vec2();
layout.push_layout(pos, child);
}
@@ -359,7 +345,7 @@ impl StackLayouter {
}
}
-/// A layout space composed of subspaces which can have different systems and
+/// A layout space composed of subspaces which can have different directions and
/// alignments.
struct Space {
/// The index of this space in `ctx.spaces`.
@@ -367,7 +353,7 @@ 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<(LayoutSystem, LayoutAlign, BoxLayout)>,
+ layouts: Vec<(Gen2<Dir>, Gen2<GenAlign>, BoxLayout)>,
/// The specialized size of this space.
size: Size,
/// The specialized remaining space.
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 435b7109..4e53cedc 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -26,7 +26,7 @@ impl<'a> TreeLayouter<'a> {
fn new(ctx: &'a mut LayoutContext) -> Self {
let layouter = LineLayouter::new(LineContext {
spaces: ctx.constraints.spaces.clone(),
- sys: ctx.state.sys,
+ dirs: ctx.state.dirs,
repeat: ctx.constraints.repeat,
line_spacing: ctx.state.text.line_spacing(),
});
@@ -89,14 +89,12 @@ impl<'a> TreeLayouter<'a> {
fn layout_space(&mut self) {
self.layouter
- .add_primary_spacing(self.ctx.state.text.word_spacing(), SpacingKind::WORD);
+ .add_cross_spacing(self.ctx.state.text.word_spacing(), SpacingKind::WORD);
}
fn layout_parbreak(&mut self) {
- self.layouter.add_secondary_spacing(
- self.ctx.state.text.par_spacing(),
- SpacingKind::PARAGRAPH,
- );
+ self.layouter
+ .add_main_spacing(self.ctx.state.text.par_spacing(), SpacingKind::PARAGRAPH);
}
async fn layout_text(&mut self, text: &str) {
@@ -117,14 +115,14 @@ impl<'a> TreeLayouter<'a> {
let boxed = shaping::shape(
text,
self.ctx.state.text.font_size(),
- self.ctx.state.sys.primary,
+ self.ctx.state.dirs.cross,
&mut self.ctx.loader.borrow_mut(),
&self.ctx.state.text.fallback,
variant,
)
.await;
- self.layouter.add(boxed, self.ctx.state.align);
+ self.layouter.add(boxed, self.ctx.state.aligns);
}
async fn layout_heading(&mut self, heading: &NodeHeading) {
@@ -187,10 +185,10 @@ impl<'a> TreeLayouter<'a> {
match command {
LayoutSyntaxTree(tree) => self.layout_tree(&tree).await,
- Add(layout, align) => self.layouter.add(layout, align),
+ Add(layout, aligns) => self.layouter.add(layout, aligns),
AddSpacing(space, kind, axis) => match axis {
- GenAxis::Primary => self.layouter.add_primary_spacing(space, kind),
- GenAxis::Secondary => self.layouter.add_secondary_spacing(space, kind),
+ GenAxis::Main => self.layouter.add_main_spacing(space, kind),
+ GenAxis::Cross => self.layouter.add_cross_spacing(space, kind),
},
BreakLine => self.layouter.finish_line(),
@@ -219,7 +217,7 @@ impl<'a> TreeLayouter<'a> {
let space = LayoutSpace {
size: style.size,
insets: style.insets(),
- expansion: LayoutExpansion::new(true, true),
+ expansion: Spec2::new(true, true),
};
self.constraints.base = space.usable();
self.layouter.set_spaces(vec![space], true);
@@ -230,12 +228,7 @@ impl<'a> TreeLayouter<'a> {
));
}
}
-
- SetAlignment(align) => self.ctx.state.align = align,
- SetSystem(sys) => {
- self.layouter.set_sys(sys);
- self.ctx.state.sys = sys;
- }
+ SetAlignment(aligns) => self.ctx.state.aligns = aligns,
}
}
}