summaryrefslogtreecommitdiff
path: root/src/layout/stack.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-08-03 16:01:23 +0200
committerLaurenz <laurmaedje@gmail.com>2020-08-03 16:04:55 +0200
commitdbfb3d2ced91e56314dfabbb4df9a338926c0a7a (patch)
tree678264cb18f8abc81ebe28077f5aef2df4e5a4bd /src/layout/stack.rs
parent5a8f2fb73ddafba9fdbe952385ae2676126183ae (diff)
Formatting, documentation and small improvements 🧽
Diffstat (limited to 'src/layout/stack.rs')
-rw-r--r--src/layout/stack.rs122
1 files changed, 58 insertions, 64 deletions
diff --git a/src/layout/stack.rs b/src/layout/stack.rs
index 28da74b7..62f2c976 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -1,11 +1,9 @@
-//! The stack layouter arranges boxes along the secondary layouting axis.
+//! Arranging boxes into a stack along the secondary axis.
//!
-//! Individual layouts can be aligned at origin / center / end on both axes and
-//! these alignments are with respect to the growable layout space and not the
-//! total possible size.
-//!
-//! This means that a later layout can have influence on the position of an
-//! earlier one. Consider, for example, the following code:
+//! 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
+//! and not the total usable size. This means that a later layout can have
+//! influence on the position of an earlier one. Consider the following example.
//! ```typst
//! [align: right][A word.]
//! [align: left][A sentence with a couple more words.]
@@ -25,38 +23,35 @@ use crate::geom::Value4;
use super::*;
/// Performs the stack layouting.
-#[derive(Debug)]
pub struct StackLayouter {
- /// The context for layouting.
ctx: StackContext,
- /// The output layouts.
layouts: MultiLayout,
- /// The currently active layout space.
+ /// The in-progress space.
space: Space,
}
/// The context for stack layouting.
#[derive(Debug, Clone)]
pub struct StackContext {
- /// The spaces to layout in.
+ /// The spaces to layout into.
pub spaces: LayoutSpaces,
- /// The initial layouting axes, which can be updated by the
- /// [`StackLayouter::set_axes`] method.
+ /// The initial layouting axes, which can be updated through `set_axes`.
pub axes: LayoutAxes,
- /// Which alignment to set on the resulting layout. This affects how it will
- /// be positioned in a parent box.
+ /// The alignment of the _resulting_ layout. This does not effect the line
+ /// layouting itself, but rather how the finished layout will be positioned
+ /// in a parent layout.
pub align: LayoutAlign,
- /// Whether to have repeated spaces or to use only the first and only once.
+ /// Whether to spill over into copies of the last space or finish layouting
+ /// when the last space is used up.
pub repeat: bool,
}
/// A layout space composed of subspaces which can have different axes and
/// alignments.
-#[derive(Debug)]
struct Space {
- /// The index of this space in the list of spaces.
+ /// The index of this space in `ctx.spaces`.
index: usize,
- /// Whether to add the layout for this space even if it would be empty.
+ /// Whether to include a layout for this space even if it would be empty.
hard: bool,
/// The so-far accumulated layouts.
layouts: Vec<(LayoutAxes, BoxLayout)>,
@@ -66,18 +61,20 @@ struct Space {
usable: Size,
/// The specialized extra-needed size to affect the size at all.
extra: Size,
- /// The rulers of a space dictate which alignments for new boxes are still
- /// allowed and which require a new space to be started.
+ /// Dictate which alignments for new boxes are still allowed and which
+ /// require a new space to be started. For example, after an `End`-aligned
+ /// item, no `Start`-aligned one can follow.
rulers: Value4<GenAlign>,
- /// The last added spacing if the last added thing was spacing.
+ /// The spacing state. This influences how new spacing is handled, e.g. hard
+ /// spacing may override soft spacing.
last_spacing: LastSpacing,
}
impl StackLayouter {
/// Create a new stack layouter.
- pub fn new(ctx: StackContext) -> StackLayouter {
+ pub fn new(ctx: StackContext) -> Self {
let space = ctx.spaces[0];
- StackLayouter {
+ Self {
ctx,
layouts: MultiLayout::new(),
space: Space::new(0, true, space.usable()),
@@ -87,8 +84,8 @@ impl StackLayouter {
/// Add a layout to the stack.
pub fn add(&mut self, layout: BoxLayout) {
// If the alignment cannot be fitted in this space, finish it.
- // TODO: Issue warning for non-fitting alignment in
- // non-repeating context.
+ // TODO: Issue warning for non-fitting alignment in non-repeating
+ // context.
if !self.update_rulers(layout.align) && self.ctx.repeat {
self.finish_space(true);
}
@@ -116,14 +113,14 @@ impl StackLayouter {
/// Add multiple layouts to the stack.
///
- /// This function simply calls `add` repeatedly for each layout.
+ /// This is equivalent to calling `add` repeatedly for each layout.
pub fn add_multiple(&mut self, layouts: MultiLayout) {
for layout in layouts {
self.add(layout);
}
}
- /// Add secondary spacing to the stack.
+ /// Add spacing to the stack.
pub fn add_spacing(&mut self, mut spacing: f64, kind: SpacingKind) {
match kind {
// A hard space is simply an empty box.
@@ -133,11 +130,14 @@ impl StackLayouter {
let size = Size::with_y(spacing);
self.update_metrics(size);
- self.space.layouts.push((self.ctx.axes, BoxLayout {
- size: size.specialized(self.ctx.axes),
- align: LayoutAlign::new(Start, Start),
- elements: LayoutElements::new(),
- }));
+ self.space.layouts.push((
+ self.ctx.axes,
+ BoxLayout {
+ size: size.specialized(self.ctx.axes),
+ align: LayoutAlign::new(Start, Start),
+ elements: LayoutElements::new(),
+ }
+ ));
self.space.last_spacing = LastSpacing::Hard;
}
@@ -158,8 +158,6 @@ impl StackLayouter {
}
}
- /// Update the size metrics to reflect that a layout or spacing with the
- /// given generalized size has been added.
fn update_metrics(&mut self, added: Size) {
let axes = self.ctx.axes;
@@ -177,31 +175,29 @@ impl StackLayouter {
*self.space.usable.secondary_mut(axes) -= added.y;
}
- /// Update the rulers to account for the new layout. Returns true if a
- /// space break is necessary.
+ /// Returns true if a space break is necessary.
fn update_rulers(&mut self, align: LayoutAlign) -> bool {
let allowed = self.is_fitting_alignment(align);
if allowed {
- *self.space.rulers.get_mut(self.ctx.axes.secondary, Start)
- = align.secondary;
+ *self.space.rulers.get_mut(self.ctx.axes.secondary, Start) =
+ align.secondary;
}
allowed
}
- /// Whether a layout with the given alignment can still be layouted in the
- /// active space.
- pub fn is_fitting_alignment(&mut self, align: LayoutAlign) -> bool {
+ /// 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(&mut self, align: LayoutAlign) -> bool {
self.is_fitting_axis(self.ctx.axes.primary, align.primary)
&& self.is_fitting_axis(self.ctx.axes.secondary, align.secondary)
}
- /// Whether the given alignment is still allowed according to the rulers.
fn is_fitting_axis(&mut self, dir: Dir, align: GenAlign) -> bool {
align >= *self.space.rulers.get_mut(dir, Start)
- && align <= self.space.rulers.get_mut(dir, End).inv()
+ && align <= self.space.rulers.get_mut(dir, End).inv()
}
- /// Change the layouting axes used by this layouter.
+ /// Update the layouting axes.
pub fn set_axes(&mut self, axes: LayoutAxes) {
// Forget the spacing because it is not relevant anymore.
if axes.secondary != self.ctx.axes.secondary {
@@ -211,10 +207,10 @@ impl StackLayouter {
self.ctx.axes = axes;
}
- /// Change the layouting spaces to use.
+ /// Update the layouting spaces.
///
/// If `replace_empty` is true, the current space is replaced if there are
- /// no boxes laid into it yet. Otherwise, only the followup spaces are
+ /// no boxes laid out into it yet. Otherwise, the followup spaces are
/// replaced.
pub fn set_spaces(&mut self, spaces: LayoutSpaces, replace_empty: bool) {
if replace_empty && self.space_is_empty() {
@@ -234,13 +230,13 @@ impl StackLayouter {
if space.usable().fits(size) {
self.finish_space(true);
self.start_space(start + index, true);
- return;
+ break;
}
}
}
- /// The remaining unpadded, unexpanding spaces. If a function is laid out
- /// into these spaces, it will fit into this stack.
+ /// The remaining inner spaces. If something is laid out into these spaces,
+ /// it will fit into this stack.
pub fn remaining(&self) -> LayoutSpaces {
let size = self.usable();
@@ -251,7 +247,7 @@ impl StackLayouter {
}];
for space in &self.ctx.spaces[self.next_space()..] {
- spaces.push(space.usable_space());
+ spaces.push(space.inner());
}
spaces
@@ -264,17 +260,17 @@ impl StackLayouter {
.specialized(self.ctx.axes)
}
- /// Whether the current layout space (not subspace) is empty.
+ /// Whether the current layout space is empty.
pub fn space_is_empty(&self) -> bool {
self.space.size == Size::ZERO && self.space.layouts.is_empty()
}
- /// Whether the current layout space is the last is the followup list.
+ /// Whether the current layout space is the last in the followup list.
pub fn space_is_last(&self) -> bool {
self.space.index == self.ctx.spaces.len() - 1
}
- /// Compute the finished list of boxes.
+ /// Finish everything up and return the final collection of boxes.
pub fn finish(mut self) -> MultiLayout {
if self.space.hard || !self.space_is_empty() {
self.finish_space(false);
@@ -282,7 +278,7 @@ impl StackLayouter {
self.layouts
}
- /// Finish the current space and start a new one.
+ /// Finish active current space and start a new one.
pub fn finish_space(&mut self, hard: bool) {
let space = self.ctx.spaces[self.space.index];
@@ -322,8 +318,8 @@ impl StackLayouter {
// layout uses up space from the origin to the end. Thus, it reduces
// the usable space for following layouts at it's origin by its
// extent along the secondary axis.
- *bound.get_mut(axes.secondary, Start)
- += axes.secondary.factor() * layout.size.secondary(*axes);
+ *bound.get_mut(axes.secondary, Start) +=
+ axes.secondary.factor() * layout.size.secondary(*axes);
}
// ------------------------------------------------------------------ //
@@ -351,8 +347,8 @@ impl StackLayouter {
// We reduce the bounding box of this layout at it's end by the
// accumulated secondary extent of all layouts we have seen so far,
// which are the layouts after this one since we iterate reversed.
- *bound.get_mut(axes.secondary, End)
- -= axes.secondary.factor() * extent.y;
+ *bound.get_mut(axes.secondary, End) -=
+ axes.secondary.factor() * extent.y;
// Then, we add this layout's secondary extent to the accumulator.
let size = layout.size.generalized(*axes);
@@ -395,21 +391,19 @@ impl StackLayouter {
self.start_space(self.next_space(), hard)
}
- /// Start a new space with the given index.
fn start_space(&mut self, index: usize, hard: bool) {
let space = self.ctx.spaces[index];
self.space = Space::new(index, hard, space.usable());
}
- /// The index of the next space.
fn next_space(&self) -> usize {
(self.space.index + 1).min(self.ctx.spaces.len() - 1)
}
}
impl Space {
- fn new(index: usize, hard: bool, usable: Size) -> Space {
- Space {
+ fn new(index: usize, hard: bool, usable: Size) -> Self {
+ Self {
index,
hard,
layouts: vec![],