Add margins with basic box layouter 📖
This commit is contained in:
parent
c4eb4ee362
commit
221934df4b
@ -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
37
src/layout/boxed.rs
Normal 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
|
||||
})
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
23
src/lib.rs
23
src/lib.rs
@ -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()))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user