summaryrefslogtreecommitdiff
path: root/src/layout/mod.rs
blob: efb2f169fcc4df9ba2211e37b15eff6a3ffd1a65 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Layouting of syntax trees into box layouts.

pub mod elements;
pub mod line;
pub mod primitive;
pub mod stack;
pub mod text;
mod tree;

/// Basic types used across the layouting engine.
pub mod prelude {
    pub use super::primitive::*;
    pub use super::{BoxLayout, layout, LayoutContext, LayoutSpace, MultiLayout};
    pub use Dir::*;
    pub use GenAlign::*;
    pub use GenAxis::*;
    pub use SpecAlign::*;
    pub use SpecAxis::*;
}

pub use primitive::*;
pub use tree::layout_tree as layout;

use crate::compute::scope::Scope;
use crate::font::SharedFontLoader;
use crate::geom::{Margins, Size};
use crate::style::{LayoutStyle, PageStyle, TextStyle};
use crate::syntax::tree::SyntaxTree;

use elements::LayoutElements;
use prelude::*;

/// A collection of layouts.
pub type MultiLayout = Vec<BoxLayout>;

/// A finished box with content at fixed positions.
#[derive(Debug, Clone, PartialEq)]
pub struct BoxLayout {
    /// The size of the box.
    pub size: Size,
    /// How to align this box in a parent container.
    pub align: LayoutAlign,
    /// The elements composing this layout.
    pub elements: LayoutElements,
}

/// The context for layouting.
#[derive(Debug, Clone)]
pub struct LayoutContext<'a> {
    /// The font loader to query fonts from when typesetting text.
    pub loader: &'a SharedFontLoader,
    /// The function scope.
    pub scope: &'a Scope,
    /// The style for pages and text.
    pub style: &'a LayoutStyle,
    /// The unpadded size of this container (the base 100% for relative sizes).
    pub base: Size,
    /// The spaces to layout into.
    pub spaces: LayoutSpaces,
    /// Whether to spill over into copies of the last space or finish layouting
    /// when the last space is used up.
    pub repeat: bool,
    /// The axes along which content is laid out.
    pub axes: LayoutAxes,
    /// The alignment of the _resulting_ layout. This does not effect the line
    /// layouting itself, but rather how the finished layout will be positioned
    /// in a parent layout.
    pub align: LayoutAlign,
    /// Whether this layouting process is the root page-building process.
    pub root: bool,
}

/// A collection of layout spaces.
pub type LayoutSpaces = Vec<LayoutSpace>;

/// The space into which content is laid out.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LayoutSpace {
    /// The maximum size of the rectangle to layout into.
    pub size: Size,
    /// Padding that should be respected on each side.
    pub padding: Margins,
    /// Whether to expand the size of the resulting layout to the full size of
    /// this space or to shrink it to fit the content.
    pub expansion: LayoutExpansion,
}

impl LayoutSpace {
    /// The offset from the origin to the start of content, i.e.
    /// `(padding.left, padding.top)`.
    pub fn start(&self) -> Size {
        Size::new(self.padding.left, self.padding.top)
    }

    /// The actually usable area (size minus padding).
    pub fn usable(&self) -> Size {
        self.size.unpadded(self.padding)
    }

    /// The inner layout space with size reduced by the padding, zero padding of
    /// its own and no layout expansion.
    pub fn inner(&self) -> Self {
        Self {
            size: self.usable(),
            padding: Margins::ZERO,
            expansion: LayoutExpansion::new(false, false),
        }
    }
}

/// A sequence of layouting commands.
pub type Commands = Vec<Command>;

/// Commands executable by the layouting engine.
#[derive(Debug, Clone, PartialEq)]
pub enum Command {
    /// Layout the given tree in the current context (i.e. not nested). The
    /// content of the tree is not laid out into a separate box and then added,
    /// but simply laid out flatly in the active layouting process.
    ///
    /// This has the effect that the content fits nicely into the active line
    /// layouting, enabling functions to e.g. change the style of some piece of
    /// text while keeping it part of the current paragraph.
    LayoutSyntaxTree(SyntaxTree),

    /// Add a finished layout.
    Add(BoxLayout),
    /// Add multiple layouts, one after another. This is equivalent to multiple
    /// `Add` commands.
    AddMultiple(MultiLayout),

    /// Add spacing of the given kind along the primary or secondary axis. The
    /// kind defines how the spacing interacts with surrounding spacing.
    AddSpacing(f64, SpacingKind, GenAxis),

    /// Start a new line.
    BreakLine,
    /// Start a new page, which will be part of the finished layout even if it
    /// stays empty (since the page break is a _hard_ space break).
    BreakPage,

    /// Update the text style.
    SetTextStyle(TextStyle),
    /// Update the page style.
    SetPageStyle(PageStyle),

    /// Update the alignment for future boxes added to this layouting process.
    SetAlignment(LayoutAlign),
    /// Update the layouting axes along which future boxes will be laid
    /// out. This ends the current line.
    SetAxes(LayoutAxes),
}