summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-10-17 19:21:47 +0200
committerLaurenz <laurmaedje@gmail.com>2019-10-17 19:21:47 +0200
commit991e879e1d2ed53125dbff4edba80804ff28f2a9 (patch)
tree0917f83108feca10ca4207dd9089fe57cf8098d5 /src
parent1987e5861cf2c033e3a540a5ef7c0f7106016929 (diff)
Extend stack layouts from vertical to horizontal flows ➡
Diffstat (limited to 'src')
-rw-r--r--src/export/pdf.rs6
-rw-r--r--src/layout/flex.rs2
-rw-r--r--src/layout/mod.rs9
-rw-r--r--src/layout/stacked.rs56
-rw-r--r--src/layout/tree.rs1
-rw-r--r--src/lib.rs3
-rw-r--r--src/library/boxed.rs34
7 files changed, 84 insertions, 27 deletions
diff --git a/src/export/pdf.rs b/src/export/pdf.rs
index f029a37f..bb688118 100644
--- a/src/export/pdf.rs
+++ b/src/export/pdf.rs
@@ -146,8 +146,10 @@ impl<'d, W: Write> ExportProcess<'d, W> {
for index in 0 .. num_fonts {
let old_index = new_to_old[&index];
let font = font_loader.get_with_index(old_index);
- let subsetted = font.subsetted(font_chars[&old_index].iter().cloned(), &SUBSET_TABLES)?;
- fonts.push(OwnedFont::from_bytes(subsetted)?);
+ let subsetted = font.subsetted(font_chars[&old_index].iter().cloned(), &SUBSET_TABLES)
+ .map(|bytes| OwnedFont::from_bytes(bytes))
+ .unwrap_or_else(|_| font.to_owned())?;
+ fonts.push(subsetted);
}
Ok((fonts, old_to_new))
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index a6f2e091..b97b4239 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -90,7 +90,7 @@ impl FlexLayouter {
ctx,
units: vec![],
- stack: StackLayouter::new(StackContext::from_flex_ctx(ctx)),
+ stack: StackLayouter::new(StackContext::from_flex_ctx(ctx, Flow::Vertical)),
usable_width: ctx.space.usable().x,
run: FlexRun {
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index fccbe8c8..470ac3ba 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -134,6 +134,8 @@ pub struct LayoutContext<'a, 'p> {
pub style: &'a TextStyle,
/// The alignment to use for the content.
pub alignment: Alignment,
+ /// How to stack the context.
+ pub flow: Flow,
/// The primary space to layout in.
pub space: LayoutSpace,
/// The additional spaces which are used when the primary space
@@ -176,6 +178,13 @@ pub enum Alignment {
Center,
}
+/// The flow of content.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum Flow {
+ Vertical,
+ Horizontal,
+}
+
/// The error type for layouting.
pub enum LayoutError {
/// There is not enough space to add an item.
diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs
index d87e5394..0097ce3e 100644
--- a/src/layout/stacked.rs
+++ b/src/layout/stacked.rs
@@ -26,15 +26,17 @@ pub struct StackContext {
pub space: LayoutSpace,
pub followup_spaces: Option<LayoutSpace>,
pub shrink_to_fit: bool,
+ pub flow: Flow,
}
macro_rules! reuse {
- ($ctx:expr) => {
+ ($ctx:expr, $flow:expr) => {
StackContext {
alignment: $ctx.alignment,
space: $ctx.space,
followup_spaces: $ctx.followup_spaces,
- shrink_to_fit: $ctx.shrink_to_fit
+ shrink_to_fit: $ctx.shrink_to_fit,
+ flow: $flow
}
};
}
@@ -42,12 +44,12 @@ macro_rules! reuse {
impl StackContext {
/// Create a stack context from a generic layout context.
pub fn from_layout_ctx(ctx: LayoutContext) -> StackContext {
- reuse!(ctx)
+ reuse!(ctx, ctx.flow)
}
/// Create a stack context from a flex context.
- pub fn from_flex_ctx(ctx: FlexContext) -> StackContext {
- reuse!(ctx)
+ pub fn from_flex_ctx(ctx: FlexContext, flow: Flow) -> StackContext {
+ reuse!(ctx, flow)
}
}
@@ -79,9 +81,15 @@ impl StackLayouter {
self.start_new_space()?;
}
- let new_dimensions = Size2D {
- x: crate::size::max(self.dimensions.x, layout.dimensions.x),
- y: self.dimensions.y + layout.dimensions.y,
+ let new_dimensions = match self.ctx.flow {
+ Flow::Vertical => Size2D {
+ x: crate::size::max(self.dimensions.x, layout.dimensions.x),
+ y: self.dimensions.y + layout.dimensions.y,
+ },
+ Flow::Horizontal => Size2D {
+ x: self.dimensions.x + layout.dimensions.x,
+ y: crate::size::max(self.dimensions.y, layout.dimensions.y),
+ }
};
if self.overflows(new_dimensions) {
@@ -104,9 +112,13 @@ impl StackLayouter {
Alignment::Center => self.cursor - Size2D::with_x(layout.dimensions.x / 2),
};
- self.cursor.y += layout.dimensions.y;
self.dimensions = new_dimensions;
+ match self.ctx.flow {
+ Flow::Vertical => self.cursor.y += layout.dimensions.y,
+ Flow::Horizontal => self.cursor.x += layout.dimensions.x,
+ }
+
self.actions.add_layout(position, layout);
Ok(())
@@ -120,23 +132,26 @@ impl StackLayouter {
Ok(())
}
- /// Add vertical space after the last layout.
+ /// Add space after the last layout.
pub fn add_space(&mut self, space: Size) -> LayoutResult<()> {
if !self.started {
self.start_new_space()?;
}
- let new_dimensions = self.dimensions + Size2D::with_y(space);
+ let new_space = match self.ctx.flow {
+ Flow::Vertical => Size2D::with_y(space),
+ Flow::Horizontal => Size2D::with_x(space),
+ };
- if self.overflows(new_dimensions) {
+ if self.overflows(self.dimensions + new_space) {
if self.ctx.followup_spaces.is_some() {
self.finish_layout(false)?;
} else {
return Err(LayoutError::NotEnoughSpace("cannot fit space into stack"));
}
} else {
- self.cursor.y += space;
- self.dimensions.y += space;
+ self.cursor += new_space;
+ self.dimensions += new_space;
}
Ok(())
@@ -195,10 +210,17 @@ impl StackLayouter {
/// The remaining space for new layouts.
pub fn remaining(&self) -> Size2D {
- Size2D {
- x: self.usable.x,
- y: self.usable.y - self.dimensions.y,
+ match self.ctx.flow {
+ Flow::Vertical => Size2D {
+ x: self.usable.x,
+ y: self.usable.y - self.dimensions.y,
+ },
+ Flow::Horizontal => Size2D {
+ x: self.usable.x - self.dimensions.x,
+ y: self.usable.y,
+ },
}
+
}
/// Whether the active space of this layouter contains no content.
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 2c904369..3a58115f 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -96,6 +96,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
let mut ctx = self.ctx;
ctx.style = &self.style;
+ ctx.flow = Flow::Vertical;
ctx.shrink_to_fit = true;
ctx.space.dimensions = remaining;
ctx.space.padding = SizeBox::zero();
diff --git a/src/lib.rs b/src/lib.rs
index c01e5d7e..0b559be9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,7 +21,7 @@ use toddle::query::{FontLoader, FontProvider, SharedFontLoader};
use crate::func::Scope;
use crate::layout::{layout_tree, LayoutContext, MultiLayout};
-use crate::layout::{Alignment, LayoutError, LayoutResult, LayoutSpace};
+use crate::layout::{Alignment, Flow, LayoutError, LayoutResult, LayoutSpace};
use crate::parsing::{parse, ParseContext, ParseError, ParseResult};
use crate::style::{PageStyle, TextStyle};
use crate::syntax::SyntaxTree;
@@ -105,6 +105,7 @@ impl<'p> Typesetter<'p> {
loader: &self.loader,
style: &self.text_style,
alignment: Alignment::Left,
+ flow: Flow::Vertical,
space,
followup_spaces: Some(space),
shrink_to_fit: false,
diff --git a/src/library/boxed.rs b/src/library/boxed.rs
index 975888f4..71a184a6 100644
--- a/src/library/boxed.rs
+++ b/src/library/boxed.rs
@@ -1,21 +1,39 @@
use super::prelude::*;
+use crate::layout::Flow;
/// Wraps content into a box.
#[derive(Debug, PartialEq)]
pub struct BoxFunc {
- body: SyntaxTree
+ body: SyntaxTree,
+ flow: Flow,
}
impl Function for BoxFunc {
fn parse(header: &FuncHeader, body: Option<&str>, ctx: ParseContext) -> ParseResult<Self>
where Self: Sized {
- if has_arguments(header) {
- return err("pagebreak: expected no arguments");
- }
+ let flow = if header.args.is_empty() {
+ Flow::Vertical
+ } else if header.args.len() == 1 {
+ if let Expression::Ident(ident) = &header.args[0] {
+ match ident.as_str() {
+ "vertical" => Flow::Vertical,
+ "horizontal" => Flow::Horizontal,
+ f => return err(format!("invalid flow specifier: '{}'", f)),
+ }
+ } else {
+ return err(format!(
+ "expected alignment specifier, found: '{}'",
+ header.args[0]
+ ));
+ }
+ } else {
+ return err("box: expected flow specifier or no arguments");
+ };
if let Some(body) = body {
Ok(BoxFunc {
- body: parse(body, ctx)?
+ body: parse(body, ctx)?,
+ flow,
})
} else {
err("box: expected body")
@@ -23,7 +41,11 @@ impl Function for BoxFunc {
}
fn layout(&self, ctx: LayoutContext) -> LayoutResult<CommandList> {
- let layout = layout_tree(&self.body, ctx)?;
+ let layout = layout_tree(&self.body, LayoutContext {
+ flow: self.flow,
+ .. ctx
+ })?;
+
Ok(commands![Command::AddMany(layout)])
}
}