summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/flex.rs6
-rw-r--r--src/layout/mod.rs39
-rw-r--r--src/layout/stack.rs27
-rw-r--r--src/layout/text.rs6
-rw-r--r--src/layout/tree.rs21
5 files changed, 67 insertions, 32 deletions
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index 48853863..72878a29 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -66,6 +66,7 @@ pub struct FlexContext {
pub axes: LayoutAxes,
pub alignment: LayoutAlignment,
pub flex_spacing: Size,
+ pub repeat: bool,
pub debug: bool,
}
@@ -76,6 +77,7 @@ impl FlexLayouter {
spaces: ctx.spaces,
axes: ctx.axes,
alignment: ctx.alignment,
+ repeat: ctx.repeat,
debug: ctx.debug,
});
@@ -144,7 +146,7 @@ impl FlexLayouter {
pub fn finish(mut self) -> LayoutResult<MultiLayout> {
self.finish_space(false)?;
- Ok(self.stack.finish())
+ self.stack.finish()
}
pub fn finish_space(&mut self, hard: bool) -> LayoutResult<()> {
@@ -152,7 +154,7 @@ impl FlexLayouter {
self.finish_run()?;
}
- self.stack.finish_space(hard);
+ self.stack.finish_space(hard)?;
Ok(self.start_line())
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 58c56dd4..b2b10264 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -16,7 +16,7 @@ mod text;
/// Common types for layouting.
pub mod prelude {
pub use super::{
- layout_tree, LayoutResult,
+ layout, LayoutResult,
MultiLayout, Layout, LayoutContext, LayoutSpaces, LayoutSpace,
LayoutExpansion, LayoutAxes, GenericAxis, SpecificAxis, Direction,
LayoutAlignment, Alignment, SpacingKind,
@@ -29,7 +29,7 @@ pub mod prelude {
/// Different kinds of layouters (fully re-exported).
pub mod layouters {
- pub use super::tree::layout_tree;
+ pub use super::tree::layout;
pub use super::flex::{FlexLayouter, FlexContext};
pub use super::stack::{StackLayouter, StackContext};
pub use super::text::{layout_text, TextContext};
@@ -107,10 +107,11 @@ pub struct LayoutContext<'a, 'p> {
pub loader: &'a SharedFontLoader<'p>,
/// The style for pages and text.
pub style: &'a LayoutStyle,
+ /// The base unpadded dimensions of this container (for relative sizing).
+ pub base: Size2D,
/// The spaces to layout in.
pub spaces: LayoutSpaces,
- /// Whether to repeat the last space or quit with an error if more space
- /// would be needed.
+ /// Whether to have repeated spaces or to use only the first and only once.
pub repeat: bool,
/// The initial axes along which content is laid out.
pub axes: LayoutAxes,
@@ -172,6 +173,14 @@ impl LayoutExpansion {
pub fn new(horizontal: bool, vertical: bool) -> LayoutExpansion {
LayoutExpansion { horizontal, vertical }
}
+
+ /// Borrow the spcified component mutably.
+ pub fn get_mut(&mut self, axis: SpecificAxis) -> &mut bool {
+ match axis {
+ Horizontal => &mut self.horizontal,
+ Vertical => &mut self.vertical,
+ }
+ }
}
/// The axes along which the content is laid out.
@@ -192,16 +201,24 @@ impl LayoutAxes {
}
/// Return the direction of the specified generic axis.
- pub fn get_generic(self, axis: GenericAxis) -> Direction {
+ pub fn get(self, axis: GenericAxis) -> Direction {
match axis {
Primary => self.primary,
Secondary => self.secondary,
}
}
+ /// Borrow the direction of the specified generic axis mutably.
+ pub fn get_mut(&mut self, axis: GenericAxis) -> &mut Direction {
+ match axis {
+ Primary => &mut self.primary,
+ Secondary => &mut self.secondary,
+ }
+ }
+
/// Return the direction of the specified specific axis.
pub fn get_specific(self, axis: SpecificAxis) -> Direction {
- self.get_generic(axis.to_generic(self))
+ self.get(axis.to_generic(self))
}
}
@@ -215,7 +232,7 @@ pub enum GenericAxis {
impl GenericAxis {
/// The specific version of this axis in the given system of axes.
pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis {
- axes.get_generic(self).axis()
+ axes.get(self).axis()
}
/// The other axis.
@@ -306,11 +323,11 @@ impl LayoutAlignment {
LayoutAlignment { primary, secondary }
}
- /// Return the alignment of the specified generic axis.
- pub fn get(self, axis: GenericAxis) -> Alignment {
+ /// Borrow the alignment of the specified generic axis mutably.
+ pub fn get_mut(&mut self, axis: GenericAxis) -> &mut Alignment {
match axis {
- Primary => self.primary,
- Secondary => self.secondary,
+ Primary => &mut self.primary,
+ Secondary => &mut self.secondary,
}
}
}
diff --git a/src/layout/stack.rs b/src/layout/stack.rs
index a2ffdc9b..3c659d8a 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -27,6 +27,8 @@ pub struct StackContext {
/// Which alignment to set on the resulting layout. This affects how it will
/// be positioned in a parent box.
pub alignment: LayoutAlignment,
+ /// Whether to have repeated spaces or to use only the first and only once.
+ pub repeat: bool,
/// Whether to output a command which renders a debugging box showing the
/// extent of the layout.
pub debug: bool,
@@ -77,8 +79,9 @@ impl StackLayouter {
/// Add a layout to the stack.
pub fn add(&mut self, layout: Layout) -> LayoutResult<()> {
+ // If the alignment cannot be fit in this space, finish it.
if !self.update_rulers(layout.alignment) {
- self.finish_space(true);
+ self.finish_space(true)?;
}
// Now, we add a possibly cached soft space. If the secondary alignment
@@ -91,11 +94,11 @@ impl StackLayouter {
// Find the first space that fits the layout.
while !self.space.usable.fits(layout.dimensions) {
if self.space_is_last() && self.space_is_empty() {
- error!("box of size {} does not fit into remaining usable size {}",
+ error!("cannot fit box of size {} into usable size of {}",
layout.dimensions, self.space.usable);
}
- self.finish_space(true);
+ self.finish_space(true)?;
}
// Change the usable space and size of the space.
@@ -257,15 +260,19 @@ impl StackLayouter {
}
/// Compute the finished multi-layout.
- pub fn finish(mut self) -> MultiLayout {
+ pub fn finish(mut self) -> LayoutResult<MultiLayout> {
if self.space.hard || !self.space_is_empty() {
- self.finish_space(false);
+ self.finish_space(false)?;
}
- self.layouts
+ Ok(self.layouts)
}
/// Finish the current space and start a new one.
- pub fn finish_space(&mut self, hard: bool) {
+ pub fn finish_space(&mut self, hard: bool) -> LayoutResult<()> {
+ if !self.ctx.repeat && hard {
+ error!("cannot create new space in a non-repeating context");
+ }
+
let space = self.ctx.spaces[self.space.index];
// ------------------------------------------------------------------ //
@@ -304,7 +311,7 @@ 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, Origin)
+ *bound.get_mut(axes.secondary, Origin)
+= axes.secondary.factor() * layout.dimensions.get_secondary(*axes);
}
@@ -333,7 +340,7 @@ 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)
+ *bound.get_mut(axes.secondary, End)
-= axes.secondary.factor() * extent.y;
// Then, we add this layout's secondary extent to the accumulator.
@@ -378,7 +385,7 @@ impl StackLayouter {
// ------------------------------------------------------------------ //
// Step 5: Start the next space.
- self.start_space(self.next_space(), hard);
+ Ok(self.start_space(self.next_space(), hard))
}
/// Start a new space with the given index.
diff --git a/src/layout/text.rs b/src/layout/text.rs
index af74df13..996c5139 100644
--- a/src/layout/text.rs
+++ b/src/layout/text.rs
@@ -61,7 +61,7 @@ impl<'a, 'p> TextLayouter<'a, 'p> {
self.buffer = String::new();
}
- self.actions.add(LayoutAction::SetFont(index, self.ctx.style.font_size));
+ self.actions.add(LayoutAction::SetFont(index, self.ctx.style.font_size()));
self.active_font = index;
}
@@ -73,7 +73,7 @@ impl<'a, 'p> TextLayouter<'a, 'p> {
}
Ok(Layout {
- dimensions: Size2D::new(self.width, self.ctx.style.font_size),
+ dimensions: Size2D::new(self.width, self.ctx.style.font_size()),
alignment: self.ctx.alignment,
actions: self.actions.to_vec(),
})
@@ -108,7 +108,7 @@ impl<'a, 'p> TextLayouter<'a, 'p> {
.advance_width as f32;
let char_width = font_unit_to_size(glyph_width)
- * self.ctx.style.font_size.to_pt();
+ * self.ctx.style.font_size().to_pt();
return Ok((index, char_width));
}
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index e9d8850d..3c6a4274 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -7,7 +7,7 @@ use crate::style::TextStyle;
use super::*;
/// Layout a syntax tree into a multibox.
-pub fn layout_tree(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiLayout> {
+pub fn layout(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult<MultiLayout> {
let mut layouter = TreeLayouter::new(ctx);
layouter.layout(tree)?;
layouter.finish()
@@ -28,6 +28,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
spaces: ctx.spaces.clone(),
axes: ctx.axes,
alignment: ctx.alignment,
+ repeat: ctx.repeat,
debug: ctx.debug,
}),
style: ctx.style.clone(),
@@ -106,8 +107,15 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
FinishLine => {},
FinishRun => {},
- FinishSpace => self.stack.finish_space(true),
+ FinishSpace => self.stack.finish_space(true)?,
BreakParagraph => self.layout_paragraph()?,
+ BreakPage => {
+ if self.ctx.nested {
+ error!("page break cannot be issued from nested context");
+ }
+
+ self.stack.finish_space(true)?
+ }
SetTextStyle(style) => self.style.text = style,
SetPageStyle(style) => {
@@ -116,6 +124,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
}
self.style.page = style;
+ self.ctx.base = style.dimensions.unpadded(style.margins);
self.stack.set_spaces(smallvec![
LayoutSpace {
dimensions: style.dimensions,
@@ -135,18 +144,18 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
}
fn finish(self) -> LayoutResult<MultiLayout> {
- Ok(self.stack.finish())
+ self.stack.finish()
}
}
fn word_spacing(style: &TextStyle) -> Size {
- style.word_spacing * style.font_size
+ style.word_spacing * style.font_size()
}
fn flex_spacing(style: &TextStyle) -> Size {
- (style.line_spacing - 1.0) * style.font_size
+ (style.line_spacing - 1.0) * style.font_size()
}
fn paragraph_spacing(style: &TextStyle) -> Size {
- (style.paragraph_spacing - 1.0) * style.font_size
+ (style.paragraph_spacing - 1.0) * style.font_size()
}