//! Layouting of documents. pub mod nodes; pub mod primitive; pub use primitive::*; use async_trait::async_trait; use crate::font::SharedFontLoader; use crate::geom::{Point, Rect, Size, SizeExt}; use crate::shaping::Shaped; use nodes::Document; /// Layout a document and return the produced layouts. pub async fn layout(document: &Document, loader: SharedFontLoader) -> Vec { let mut ctx = LayoutContext { loader }; document.layout(&mut ctx).await } /// The context for layouting. #[derive(Debug, Clone)] pub struct LayoutContext { /// The font loader to query fonts from when typesetting text. pub loader: SharedFontLoader, } /// Layout a node. #[async_trait(?Send)] pub trait Layout { /// Layout the node in the given layout context. /// /// This signature looks pretty horrible due to async in trait methods, but /// it's actually just the following: /// ```rust,ignore /// async fn layout( /// &self, /// ctx: &mut LayoutContext, /// constraints: LayoutConstraints, /// ) -> Vec; /// ``` async fn layout( &self, ctx: &mut LayoutContext, constraints: LayoutConstraints, ) -> Vec; } /// An item that is produced by [layouting] a node. /// /// [layouting]: trait.Layout.html#method.layout #[derive(Debug, Clone, PartialEq)] pub enum LayoutItem { /// Spacing that should be added to the parent. Spacing(f64), /// A box that should be aligned in the parent. Box(BoxLayout, Gen2), } /// The constraints for layouting a single node. #[derive(Debug, Clone)] pub struct LayoutConstraints { /// The spaces to layout into. pub spaces: Vec, /// Whether to spill over into copies of the last space or finish layouting /// when the last space is used up. pub repeat: bool, } /// The space into which content is laid out. #[derive(Debug, Copy, Clone, PartialEq)] pub struct LayoutSpace { /// The full size of this container (the base for relative sizes). pub base: Size, /// The maximum size of the rectangle to layout into. pub size: Size, } /// A finished box with content at fixed positions. #[derive(Debug, Clone, PartialEq)] pub struct BoxLayout { /// The size of the box. pub size: Size, /// The elements composing this layout. pub elements: Vec<(Point, LayoutElement)>, } impl BoxLayout { /// Create a new empty collection. pub fn new(size: Size) -> Self { Self { size, elements: vec![] } } /// Add an element at a position. pub fn push(&mut self, pos: Point, element: LayoutElement) { self.elements.push((pos, element)); } /// Add all elements of another collection, placing them relative to the /// given position. pub fn push_layout(&mut self, pos: Point, more: Self) { for (subpos, element) in more.elements { self.push(pos + subpos.to_vec2(), element); } } } /// A layout element, the basic building block layouts are composed of. #[derive(Debug, Clone, PartialEq)] pub enum LayoutElement { /// Shaped text. Text(Shaped), }