Add margins with basic box layouter 📖

This commit is contained in:
Laurenz Mädje 2019-06-02 18:01:22 +02:00
parent c4eb4ee362
commit 221934df4b
6 changed files with 90 additions and 24 deletions

View File

@ -1,7 +1,7 @@
//! Representation of typesetted documents.
use crate::font::Font;
use crate::layout::Size;
use crate::layout::{Size, Position};
/// A complete typesetted document, which can be exported.
@ -28,7 +28,7 @@ pub struct Page {
#[derive(Debug, Clone)]
pub enum TextAction {
/// Move from the _start_ of the current line by an (x, y) offset.
MoveNewline(Size, Size),
MoveNewline(Position),
/// Write text starting at the current position.
WriteText(String),
/// Set the font by index and font size.

37
src/layout/boxed.rs Normal file
View File

@ -0,0 +1,37 @@
//! Layouting of layout boxes.
use crate::doc::TextAction;
use super::{Layouter, Layout, LayoutContext, LayoutResult, Position};
/// Layouts sublayouts within the constraints of a layouting context.
#[derive(Debug)]
pub struct BoxLayouter<'a, 'p> {
ctx: &'a LayoutContext<'a, 'p>,
actions: Vec<TextAction>,
}
impl<'a, 'p> BoxLayouter<'a, 'p> {
/// Create a new box layouter.
pub fn new(ctx: &'a LayoutContext<'a, 'p>) -> BoxLayouter<'a, 'p> {
BoxLayouter {
ctx,
actions: vec![],
}
}
/// Add a sublayout.
pub fn add_layout_absolute(&mut self, position: Position, layout: Layout) {
self.actions.push(TextAction::MoveNewline(position));
self.actions.extend(layout.actions);
}
}
impl Layouter for BoxLayouter<'_, '_> {
fn finish(self) -> LayoutResult<Layout> {
Ok(Layout {
extent: self.ctx.max_extent.clone(),
actions: self.actions
})
}
}

View File

@ -6,9 +6,11 @@ use crate::syntax::{SyntaxTree, Node};
mod size;
mod text;
mod boxed;
pub use size::Size;
pub use size::{Size, Position, Extent};
pub use text::TextLayouter;
pub use boxed::BoxLayouter;
/// Layout a syntax tree in a given context.
@ -44,7 +46,7 @@ pub fn layout(tree: &SyntaxTree, ctx: &LayoutContext) -> LayoutResult<Layout> {
#[derive(Debug, Clone)]
pub struct Layout {
/// The extent of this layout into all directions.
extent: LayoutDimensions,
extent: Extent,
/// Actions composing this layout.
actions: Vec<TextAction>,
}
@ -75,20 +77,11 @@ pub struct LayoutContext<'a, 'p> {
/// Loads fonts matching queries.
pub loader: &'a FontLoader<'p>,
/// The spacial constraints to layout in.
pub max_extent: LayoutDimensions,
pub max_extent: Extent,
/// Base style to set text with.
pub text_style: TextStyle,
}
/// A space to layout in.
#[derive(Debug, Clone)]
pub struct LayoutDimensions {
/// Horizontal extent.
pub width: Size,
/// Vertical extent.
pub height: Size,
}
/// Default styles for text.
#[derive(Debug, Clone)]
pub struct TextStyle {

View File

@ -6,6 +6,24 @@ use std::iter::Sum;
use std::ops::*;
/// A position in 2-dimensional space.
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Position {
/// The horizontal coordinate.
pub x: Size,
/// The vertical coordinate.
pub y: Size,
}
/// Size of a box in 2-dimensional space.
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Extent {
/// The horizontal extent.
pub width: Size,
/// The vertical extent.
pub height: Size,
}
/// A general spacing type.
#[derive(Copy, Clone, PartialEq, Default)]
pub struct Size {

View File

@ -7,7 +7,7 @@ use smallvec::SmallVec;
use crate::doc::TextAction;
use crate::font::{Font, FontQuery};
use super::{Layouter, Layout, LayoutError, LayoutContext, Size, LayoutResult};
use super::{Layouter, Layout, LayoutError, LayoutContext, LayoutResult, Size, Position};
/// Layouts text within the constraints of a layouting context.
@ -208,10 +208,11 @@ impl<'a, 'p> TextFinisher<'a, 'p> {
/// Move to the top-left corner of the layout space.
fn move_start(&mut self) {
self.actions.push(TextAction::MoveNewline(
Size::zero(), self.layouter.ctx.max_extent.height
self.actions.push(TextAction::MoveNewline(Position {
x: Size::zero(),
y: self.layouter.ctx.max_extent.height
- Size::from_points(self.layouter.ctx.text_style.font_size)
));
}));
}
/// Move to the next line. A factor of 1.0 uses the default line spacing.
@ -221,7 +222,11 @@ impl<'a, 'p> TextFinisher<'a, 'p> {
* self.layouter.ctx.text_style.line_spacing
* factor;
self.actions.push(TextAction::MoveNewline(Size::zero(), -vertical));
self.actions.push(TextAction::MoveNewline(Position {
x: Size::zero(),
y: -vertical
}));
self.current_width = Size::zero();
}
}

View File

@ -48,7 +48,7 @@ use std::fmt::{self, Debug, Formatter};
use crate::doc::Document;
use crate::font::{Font, FontLoader, FontProvider};
use crate::func::Scope;
use crate::layout::{layout, Layout, LayoutContext, LayoutDimensions};
use crate::layout::{layout, Layout, Layouter, LayoutContext, BoxLayouter, Extent, Position};
use crate::layout::{PageStyle, TextStyle, LayoutResult, LayoutError};
use crate::parsing::{parse, ParseContext, ParseResult, ParseError};
use crate::syntax::SyntaxTree;
@ -115,21 +115,34 @@ impl<'p> Typesetter<'p> {
}
/// Layout a syntax tree and return the layout and the referenced font list.
#[inline]
pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<(Layout, Vec<Font>)> {
let loader = FontLoader::new(&self.font_providers);
// Prepare the layouting context.
let page = &self.page_style;
let ctx = LayoutContext {
let mut ctx = LayoutContext {
loader: &loader,
text_style: self.text_style.clone(),
max_extent: LayoutDimensions {
max_extent: Extent {
width: page.width - page.margin_left - page.margin_right,
height: page.height - page.margin_top - page.margin_bottom,
},
};
let layout = layout(&tree, &ctx)?;
// Layout the content of the page (without margins).
let content = layout(&tree, &ctx)?;
// Adjust the context for adding the margins.
ctx.max_extent = Extent {
width: page.width,
height: page.height,
};
// Add the margins.
let mut box_layouter = BoxLayouter::new(&ctx);
let start = Position { x: page.margin_left, y: page.margin_top };
box_layouter.add_layout_absolute(start, content);
let layout = box_layouter.finish()?;
Ok((layout, loader.into_fonts()))
}