mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Add margins with basic box layouter 📖
This commit is contained in:
parent
c4eb4ee362
commit
221934df4b
@ -1,7 +1,7 @@
|
|||||||
//! Representation of typesetted documents.
|
//! Representation of typesetted documents.
|
||||||
|
|
||||||
use crate::font::Font;
|
use crate::font::Font;
|
||||||
use crate::layout::Size;
|
use crate::layout::{Size, Position};
|
||||||
|
|
||||||
|
|
||||||
/// A complete typesetted document, which can be exported.
|
/// A complete typesetted document, which can be exported.
|
||||||
@ -28,7 +28,7 @@ pub struct Page {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TextAction {
|
pub enum TextAction {
|
||||||
/// Move from the _start_ of the current line by an (x, y) offset.
|
/// 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.
|
/// Write text starting at the current position.
|
||||||
WriteText(String),
|
WriteText(String),
|
||||||
/// Set the font by index and font size.
|
/// 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 size;
|
||||||
mod text;
|
mod text;
|
||||||
|
mod boxed;
|
||||||
|
|
||||||
pub use size::Size;
|
pub use size::{Size, Position, Extent};
|
||||||
pub use text::TextLayouter;
|
pub use text::TextLayouter;
|
||||||
|
pub use boxed::BoxLayouter;
|
||||||
|
|
||||||
|
|
||||||
/// Layout a syntax tree in a given context.
|
/// Layout a syntax tree in a given context.
|
||||||
@ -44,7 +46,7 @@ pub fn layout(tree: &SyntaxTree, ctx: &LayoutContext) -> LayoutResult<Layout> {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
/// The extent of this layout into all directions.
|
/// The extent of this layout into all directions.
|
||||||
extent: LayoutDimensions,
|
extent: Extent,
|
||||||
/// Actions composing this layout.
|
/// Actions composing this layout.
|
||||||
actions: Vec<TextAction>,
|
actions: Vec<TextAction>,
|
||||||
}
|
}
|
||||||
@ -75,20 +77,11 @@ pub struct LayoutContext<'a, 'p> {
|
|||||||
/// Loads fonts matching queries.
|
/// Loads fonts matching queries.
|
||||||
pub loader: &'a FontLoader<'p>,
|
pub loader: &'a FontLoader<'p>,
|
||||||
/// The spacial constraints to layout in.
|
/// The spacial constraints to layout in.
|
||||||
pub max_extent: LayoutDimensions,
|
pub max_extent: Extent,
|
||||||
/// Base style to set text with.
|
/// Base style to set text with.
|
||||||
pub text_style: TextStyle,
|
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.
|
/// Default styles for text.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TextStyle {
|
pub struct TextStyle {
|
||||||
|
@ -6,6 +6,24 @@ use std::iter::Sum;
|
|||||||
use std::ops::*;
|
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.
|
/// A general spacing type.
|
||||||
#[derive(Copy, Clone, PartialEq, Default)]
|
#[derive(Copy, Clone, PartialEq, Default)]
|
||||||
pub struct Size {
|
pub struct Size {
|
||||||
|
@ -7,7 +7,7 @@ use smallvec::SmallVec;
|
|||||||
|
|
||||||
use crate::doc::TextAction;
|
use crate::doc::TextAction;
|
||||||
use crate::font::{Font, FontQuery};
|
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.
|
/// 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.
|
/// Move to the top-left corner of the layout space.
|
||||||
fn move_start(&mut self) {
|
fn move_start(&mut self) {
|
||||||
self.actions.push(TextAction::MoveNewline(
|
self.actions.push(TextAction::MoveNewline(Position {
|
||||||
Size::zero(), self.layouter.ctx.max_extent.height
|
x: Size::zero(),
|
||||||
|
y: self.layouter.ctx.max_extent.height
|
||||||
- Size::from_points(self.layouter.ctx.text_style.font_size)
|
- 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.
|
/// 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
|
* self.layouter.ctx.text_style.line_spacing
|
||||||
* factor;
|
* 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();
|
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::doc::Document;
|
||||||
use crate::font::{Font, FontLoader, FontProvider};
|
use crate::font::{Font, FontLoader, FontProvider};
|
||||||
use crate::func::Scope;
|
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::layout::{PageStyle, TextStyle, LayoutResult, LayoutError};
|
||||||
use crate::parsing::{parse, ParseContext, ParseResult, ParseError};
|
use crate::parsing::{parse, ParseContext, ParseResult, ParseError};
|
||||||
use crate::syntax::SyntaxTree;
|
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.
|
/// Layout a syntax tree and return the layout and the referenced font list.
|
||||||
#[inline]
|
|
||||||
pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<(Layout, Vec<Font>)> {
|
pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<(Layout, Vec<Font>)> {
|
||||||
let loader = FontLoader::new(&self.font_providers);
|
let loader = FontLoader::new(&self.font_providers);
|
||||||
|
|
||||||
|
// Prepare the layouting context.
|
||||||
let page = &self.page_style;
|
let page = &self.page_style;
|
||||||
let ctx = LayoutContext {
|
let mut ctx = LayoutContext {
|
||||||
loader: &loader,
|
loader: &loader,
|
||||||
text_style: self.text_style.clone(),
|
text_style: self.text_style.clone(),
|
||||||
max_extent: LayoutDimensions {
|
max_extent: Extent {
|
||||||
width: page.width - page.margin_left - page.margin_right,
|
width: page.width - page.margin_left - page.margin_right,
|
||||||
height: page.height - page.margin_top - page.margin_bottom,
|
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()))
|
Ok((layout, loader.into_fonts()))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user