Refine and rename layouting types 🛀

This commit is contained in:
Laurenz 2019-12-12 23:33:26 +01:00
parent ff107cf3e7
commit f549914ff8
12 changed files with 317 additions and 372 deletions

View File

@ -12,13 +12,7 @@ mod macros;
/// Useful imports for creating your own functions. /// Useful imports for creating your own functions.
pub mod prelude { pub mod prelude {
pub use crate::func::{Scope, ParseFunc, LayoutFunc, Command, Commands}; pub use crate::func::{Scope, ParseFunc, LayoutFunc, Command, Commands};
pub use crate::layout::{ pub use crate::layout::prelude::*;
layout_tree, Layout, MultiLayout,
LayoutContext, LayoutSpace, LayoutSpaces, LayoutExpansion,
LayoutAxes, Axis, GenericAxisKind, SpecificAxisKind,
LayoutAlignment, Alignment,
SpacingKind, LayoutResult,
};
pub use crate::syntax::{ pub use crate::syntax::{
parse, ParseContext, ParseResult, parse, ParseContext, ParseResult,
SyntaxTree, FuncCall, FuncArgs, PosArg, KeyArg, SyntaxTree, FuncCall, FuncArgs, PosArg, KeyArg,
@ -107,7 +101,7 @@ pub enum Command<'a> {
Add(Layout), Add(Layout),
AddMultiple(MultiLayout), AddMultiple(MultiLayout),
AddSpacing(Size, SpacingKind, GenericAxisKind), AddSpacing(Size, SpacingKind, GenericAxis),
FinishLine, FinishLine,
FinishRun, FinishRun,
@ -149,13 +143,13 @@ impl Scope {
/// Associate the given name with a type that is parseable into a function. /// Associate the given name with a type that is parseable into a function.
pub fn add<F>(&mut self, name: &str) pub fn add<F>(&mut self, name: &str)
where F: ParseFunc<Meta=()> + LayoutFunc + 'static { where F: ParseFunc<Meta=()> + LayoutFunc + 'static {
self.add_with_metadata::<F, ()>(name, ()); self.add_with_metadata::<F>(name, ());
} }
/// Add a parseable type with additional metadata that is given to the /// Add a parseable type with additional metadata that is given to the
/// parser (other than the default of `()`). /// parser (other than the default of `()`).
pub fn add_with_metadata<F, T>(&mut self, name: &str, metadata: T) pub fn add_with_metadata<F>(&mut self, name: &str, metadata: <F as ParseFunc>::Meta)
where F: ParseFunc<Meta=T> + LayoutFunc + 'static, T: 'static + Clone { where F: ParseFunc + LayoutFunc + 'static {
self.parsers.insert( self.parsers.insert(
name.to_owned(), name.to_owned(),
Box::new(move |a, b, c| { Box::new(move |a, b, c| {

View File

@ -13,6 +13,20 @@ mod flex;
mod stack; mod stack;
mod text; mod text;
/// Common types for layouting.
pub mod prelude {
pub use super::{
layout_tree, LayoutResult,
MultiLayout, Layout, LayoutContext, LayoutSpaces, LayoutSpace,
LayoutExpansion, LayoutAxes, GenericAxis, SpecificAxis, Direction,
LayoutAlignment, Alignment, SpacingKind,
};
pub use GenericAxis::*;
pub use SpecificAxis::*;
pub use Direction::*;
pub use Alignment::*;
}
/// Different kinds of layouters (fully re-exported). /// Different kinds of layouters (fully re-exported).
pub mod layouters { pub mod layouters {
pub use super::tree::layout_tree; pub use super::tree::layout_tree;
@ -23,6 +37,7 @@ pub mod layouters {
pub use self::actions::{LayoutAction, LayoutActions}; pub use self::actions::{LayoutAction, LayoutActions};
pub use self::layouters::*; pub use self::layouters::*;
pub use self::prelude::*;
/// The result type for layouting. /// The result type for layouting.
pub type LayoutResult<T> = crate::TypesetResult<T>; pub type LayoutResult<T> = crate::TypesetResult<T>;
@ -56,6 +71,34 @@ impl Layout {
} }
} }
/// Layout components that can be serialized.
pub trait Serialize {
/// Serialize the data structure into an output writable.
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()>;
}
impl Serialize for Layout {
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
writeln!(f, "{:.4} {:.4}", self.dimensions.x.to_pt(), self.dimensions.y.to_pt())?;
writeln!(f, "{}", self.actions.len())?;
for action in &self.actions {
action.serialize(f)?;
writeln!(f)?;
}
Ok(())
}
}
impl Serialize for MultiLayout {
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
writeln!(f, "{}", self.len())?;
for layout in self {
layout.serialize(f)?;
}
Ok(())
}
}
/// The general context for layouting. /// The general context for layouting.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LayoutContext<'a, 'p> { pub struct LayoutContext<'a, 'p> {
@ -66,12 +109,16 @@ pub struct LayoutContext<'a, 'p> {
pub style: &'a LayoutStyle, pub style: &'a LayoutStyle,
/// The spaces to layout in. /// The spaces to layout in.
pub spaces: LayoutSpaces, pub spaces: LayoutSpaces,
/// Whether to repeat the last space or quit with an error if more space
/// would be needed.
pub repeat: bool,
/// The initial axes along which content is laid out. /// The initial axes along which content is laid out.
pub axes: LayoutAxes, pub axes: LayoutAxes,
/// The alignment of the finished layout. /// The alignment of the finished layout.
pub alignment: LayoutAlignment, pub alignment: LayoutAlignment,
/// Whether this layouting process handles the top-level pages. /// Whether the layout that is to be created will be nested in a parent
pub top_level: bool, /// container.
pub nested: bool,
/// Whether to debug render a box around the layout. /// Whether to debug render a box around the layout.
pub debug: bool, pub debug: bool,
} }
@ -89,7 +136,7 @@ pub struct LayoutSpace {
/// Whether to expand the dimensions of the resulting layout to the full /// Whether to expand the dimensions of the resulting layout to the full
/// dimensions of this space or to shrink them to fit the content for the /// dimensions of this space or to shrink them to fit the content for the
/// horizontal and vertical axis. /// horizontal and vertical axis.
pub expand: LayoutExpansion, pub expansion: LayoutExpansion,
} }
impl LayoutSpace { impl LayoutSpace {
@ -109,7 +156,7 @@ impl LayoutSpace {
LayoutSpace { LayoutSpace {
dimensions: self.usable(), dimensions: self.usable(),
padding: SizeBox::ZERO, padding: SizeBox::ZERO,
expand: LayoutExpansion::new(false, false), expansion: LayoutExpansion::new(false, false),
} }
} }
} }
@ -130,195 +177,125 @@ impl LayoutExpansion {
/// The axes along which the content is laid out. /// The axes along which the content is laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LayoutAxes { pub struct LayoutAxes {
pub primary: Axis, pub primary: Direction,
pub secondary: Axis, pub secondary: Direction,
} }
impl LayoutAxes { impl LayoutAxes {
pub fn new(primary: Axis, secondary: Axis) -> LayoutAxes { pub fn new(primary: Direction, secondary: Direction) -> LayoutAxes {
if primary.is_horizontal() == secondary.is_horizontal() { if primary.axis() == secondary.axis() {
panic!("LayoutAxes::new: invalid parallel axes {:?} and {:?}", primary, secondary); panic!("LayoutAxes::new: invalid aligned axes {:?} and {:?}",
primary, secondary);
} }
LayoutAxes { primary, secondary } LayoutAxes { primary, secondary }
} }
/// Return the specified generic axis. /// Return the direction of the specified generic axis.
pub fn generic(&self, axis: GenericAxisKind) -> Axis { pub fn get_generic(self, axis: GenericAxis) -> Direction {
match axis { match axis {
GenericAxisKind::Primary => self.primary, Primary => self.primary,
GenericAxisKind::Secondary => self.secondary, Secondary => self.secondary,
} }
} }
/// Return the specified specific axis. /// Return the direction of the specified specific axis.
pub fn specific(&self, axis: SpecificAxisKind) -> Axis { pub fn get_specific(self, axis: SpecificAxis) -> Direction {
self.generic(axis.generic(*self)) self.get_generic(axis.to_generic(self))
}
/// Returns the generic axis kind which is the horizontal axis.
pub fn horizontal(&self) -> GenericAxisKind {
match self.primary.is_horizontal() {
true => GenericAxisKind::Primary,
false => GenericAxisKind::Secondary,
}
}
/// Returns the generic axis kind which is the vertical axis.
pub fn vertical(&self) -> GenericAxisKind {
self.horizontal().inv()
}
/// Returns the specific axis kind which is the primary axis.
pub fn primary(&self) -> SpecificAxisKind {
match self.primary.is_horizontal() {
true => SpecificAxisKind::Horizontal,
false => SpecificAxisKind::Vertical,
}
}
/// Returns the specific axis kind which is the secondary axis.
pub fn secondary(&self) -> SpecificAxisKind {
self.primary().inv()
}
/// Returns the generic alignment corresponding to left-alignment.
pub fn left(&self) -> Alignment {
let positive = match self.primary.is_horizontal() {
true => self.primary.is_positive(),
false => self.secondary.is_positive(),
};
if positive { Alignment::Origin } else { Alignment::End }
}
/// Returns the generic alignment corresponding to right-alignment.
pub fn right(&self) -> Alignment {
self.left().inv()
}
/// Returns the generic alignment corresponding to top-alignment.
pub fn top(&self) -> Alignment {
let positive = match self.primary.is_horizontal() {
true => self.secondary.is_positive(),
false => self.primary.is_positive(),
};
if positive { Alignment::Origin } else { Alignment::End }
}
/// Returns the generic alignment corresponding to bottom-alignment.
pub fn bottom(&self) -> Alignment {
self.top().inv()
} }
} }
impl Default for LayoutAxes { /// The two generic layouting axes.
fn default() -> LayoutAxes { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
LayoutAxes { pub enum GenericAxis {
primary: Axis::LeftToRight, Primary,
secondary: Axis::TopToBottom, Secondary,
}
impl GenericAxis {
/// The specific version of this axis in the given system of axes.
pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis {
axes.get_generic(self).axis()
}
/// The other axis.
pub fn inv(self) -> GenericAxis {
match self {
Primary => Secondary,
Secondary => Primary,
}
}
}
/// The two specific layouting axes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum SpecificAxis {
Horizontal,
Vertical,
}
impl SpecificAxis {
/// The generic version of this axis in the given system of axes.
pub fn to_generic(self, axes: LayoutAxes) -> GenericAxis {
if self == axes.primary.axis() { Primary } else { Secondary }
}
/// The other axis.
pub fn inv(self) -> SpecificAxis {
match self {
Horizontal => Vertical,
Vertical => Horizontal,
} }
} }
} }
/// Directions along which content is laid out. /// Directions along which content is laid out.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum Axis { pub enum Direction {
LeftToRight, LeftToRight,
RightToLeft, RightToLeft,
TopToBottom, TopToBottom,
BottomToTop, BottomToTop,
} }
impl Axis { impl Direction {
/// Whether this is a horizontal axis. /// The specific axis this direction belongs to.
pub fn is_horizontal(&self) -> bool { pub fn axis(self) -> SpecificAxis {
match self { match self {
Axis::LeftToRight | Axis::RightToLeft => true, LeftToRight | RightToLeft => Horizontal,
Axis::TopToBottom | Axis::BottomToTop => false, TopToBottom | BottomToTop => Vertical,
} }
} }
/// Whether this axis points into the positive coordinate direction. /// Whether this axis points into the positive coordinate direction.
pub fn is_positive(&self) -> bool { pub fn is_positive(self) -> bool {
match self { match self {
Axis::LeftToRight | Axis::TopToBottom => true, LeftToRight | TopToBottom => true,
Axis::RightToLeft | Axis::BottomToTop => false, RightToLeft | BottomToTop => false,
} }
} }
/// The inverse axis. /// The inverse axis.
pub fn inv(&self) -> Axis { pub fn inv(self) -> Direction {
match self { match self {
Axis::LeftToRight => Axis::RightToLeft, LeftToRight => RightToLeft,
Axis::RightToLeft => Axis::LeftToRight, RightToLeft => LeftToRight,
Axis::TopToBottom => Axis::BottomToTop, TopToBottom => BottomToTop,
Axis::BottomToTop => Axis::TopToBottom, BottomToTop => TopToBottom,
} }
} }
/// The direction factor for this axis. /// The factor for this direction.
/// ///
/// - 1 if the axis is positive. /// - `1` if the direction is positive.
/// - -1 if the axis is negative. /// - `-1` if the direction is negative.
pub fn factor(&self) -> i32 { pub fn factor(self) -> i32 {
if self.is_positive() { 1 } else { -1 } if self.is_positive() { 1 } else { -1 }
} }
} }
/// The two generic kinds of layouting axes. /// Where to align a layout in a container.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum GenericAxisKind {
Primary,
Secondary,
}
impl GenericAxisKind {
/// The specific version of this axis in the given system of axes.
pub fn specific(&self, axes: LayoutAxes) -> SpecificAxisKind {
match self {
GenericAxisKind::Primary => axes.primary(),
GenericAxisKind::Secondary => axes.secondary(),
}
}
/// The other axis.
pub fn inv(&self) -> GenericAxisKind {
match self {
GenericAxisKind::Primary => GenericAxisKind::Secondary,
GenericAxisKind::Secondary => GenericAxisKind::Primary,
}
}
}
/// The two specific kinds of layouting axes.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum SpecificAxisKind {
Horizontal,
Vertical,
}
impl SpecificAxisKind {
/// The generic version of this axis in the given system of axes.
pub fn generic(&self, axes: LayoutAxes) -> GenericAxisKind {
match self {
SpecificAxisKind::Horizontal => axes.horizontal(),
SpecificAxisKind::Vertical => axes.vertical(),
}
}
/// The other axis.
pub fn inv(&self) -> SpecificAxisKind {
match self {
SpecificAxisKind::Horizontal => SpecificAxisKind::Vertical,
SpecificAxisKind::Vertical => SpecificAxisKind::Horizontal,
}
}
}
/// The place to put a layout in a container.
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct LayoutAlignment { pub struct LayoutAlignment {
pub primary: Alignment, pub primary: Alignment,
pub secondary: Alignment, pub secondary: Alignment,
@ -328,6 +305,14 @@ impl LayoutAlignment {
pub fn new(primary: Alignment, secondary: Alignment) -> LayoutAlignment { pub fn new(primary: Alignment, secondary: Alignment) -> LayoutAlignment {
LayoutAlignment { primary, secondary } LayoutAlignment { primary, secondary }
} }
/// Return the alignment of the specified generic axis.
pub fn get(self, axis: GenericAxis) -> Alignment {
match axis {
Primary => self.primary,
Secondary => self.secondary,
}
}
} }
/// Where to align content. /// Where to align content.
@ -340,21 +325,15 @@ pub enum Alignment {
impl Alignment { impl Alignment {
/// The inverse alignment. /// The inverse alignment.
pub fn inv(&self) -> Alignment { pub fn inv(self) -> Alignment {
match self { match self {
Alignment::Origin => Alignment::End, Origin => End,
Alignment::Center => Alignment::Center, Center => Center,
Alignment::End => Alignment::Origin, End => Origin,
} }
} }
} }
impl Default for Alignment {
fn default() -> Alignment {
Alignment::Origin
}
}
/// Whitespace between boxes with different interaction properties. /// Whitespace between boxes with different interaction properties.
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SpacingKind { pub enum SpacingKind {
@ -380,38 +359,10 @@ enum LastSpacing {
impl LastSpacing { impl LastSpacing {
/// The size of the soft space if this is a soft space or zero otherwise. /// The size of the soft space if this is a soft space or zero otherwise.
fn soft_or_zero(&self) -> Size { fn soft_or_zero(self) -> Size {
match self { match self {
LastSpacing::Soft(space, _) => *space, LastSpacing::Soft(space, _) => space,
_ => Size::ZERO, _ => Size::ZERO,
} }
} }
} }
/// Layout components that can be serialized.
pub trait Serialize {
/// Serialize the data structure into an output writable.
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()>;
}
impl Serialize for Layout {
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
writeln!(f, "{:.4} {:.4}", self.dimensions.x.to_pt(), self.dimensions.y.to_pt())?;
writeln!(f, "{}", self.actions.len())?;
for action in &self.actions {
action.serialize(f)?;
writeln!(f)?;
}
Ok(())
}
}
impl Serialize for MultiLayout {
fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
writeln!(f, "{}", self.len())?;
for layout in self {
layout.serialize(f)?;
}
Ok(())
}
}

View File

@ -125,13 +125,13 @@ impl StackLayouter {
// A hard space is simply an empty box. // A hard space is simply an empty box.
SpacingKind::Hard => { SpacingKind::Hard => {
// Reduce the spacing such that it definitely fits. // Reduce the spacing such that it definitely fits.
spacing.min_eq(self.space.usable.secondary(self.ctx.axes)); spacing.min_eq(self.space.usable.get_secondary(self.ctx.axes));
let dimensions = Size2D::with_y(spacing); let dimensions = Size2D::with_y(spacing);
self.update_metrics(dimensions); self.update_metrics(dimensions);
self.space.layouts.push((self.ctx.axes, Layout { self.space.layouts.push((self.ctx.axes, Layout {
dimensions: dimensions.specialized(self.ctx.axes), dimensions: dimensions.specialized(self.ctx.axes),
alignment: LayoutAlignment::default(), alignment: LayoutAlignment::new(Origin, Origin),
actions: vec![] actions: vec![]
})); }));
@ -169,9 +169,9 @@ impl StackLayouter {
} }
/// Whether the given alignment is still allowed according to the rulers. /// Whether the given alignment is still allowed according to the rulers.
fn alignment_allowed(&mut self, axis: Axis, alignment: Alignment) -> bool { fn alignment_allowed(&mut self, direction: Direction, alignment: Alignment) -> bool {
alignment >= *self.space.rulers.get(axis) alignment >= *self.space.rulers.get(direction)
&& alignment <= self.space.rulers.get(axis.inv()).inv() && alignment <= self.space.rulers.get(direction.inv()).inv()
} }
/// Update the size metrics to reflect that a layout or spacing with the /// Update the size metrics to reflect that a layout or spacing with the
@ -190,7 +190,7 @@ impl StackLayouter {
self.space.size = size.specialized(axes); self.space.size = size.specialized(axes);
self.space.extra = extra.specialized(axes); self.space.extra = extra.specialized(axes);
*self.space.usable.secondary_mut(axes) -= dimensions.y; *self.space.usable.get_secondary_mut(axes) -= dimensions.y;
} }
/// Change the layouting axes used by this layouter. /// Change the layouting axes used by this layouter.
@ -231,7 +231,7 @@ impl StackLayouter {
let mut spaces = smallvec![LayoutSpace { let mut spaces = smallvec![LayoutSpace {
dimensions, dimensions,
padding: SizeBox::ZERO, padding: SizeBox::ZERO,
expand: LayoutExpansion::new(false, false), expansion: LayoutExpansion::new(false, false),
}]; }];
for space in &self.ctx.spaces[self.next_space()..] { for space in &self.ctx.spaces[self.next_space()..] {
@ -243,7 +243,7 @@ impl StackLayouter {
/// The usable size along the primary axis. /// The usable size along the primary axis.
pub fn primary_usable(&self) -> Size { pub fn primary_usable(&self) -> Size {
self.space.usable.primary(self.ctx.axes) self.space.usable.get_primary(self.ctx.axes)
} }
/// Whether the current layout space (not subspace) is empty. /// Whether the current layout space (not subspace) is empty.
@ -274,8 +274,8 @@ impl StackLayouter {
// expand if necessary.) // expand if necessary.)
let usable = space.usable(); let usable = space.usable();
if space.expand.horizontal { self.space.size.x = usable.x; } if space.expansion.horizontal { self.space.size.x = usable.x; }
if space.expand.vertical { self.space.size.y = usable.y; } if space.expansion.vertical { self.space.size.y = usable.y; }
let dimensions = self.space.size.padded(space.padding); let dimensions = self.space.size.padded(space.padding);
@ -304,8 +304,8 @@ impl StackLayouter {
// layout uses up space from the origin to the end. Thus, it reduces // layout uses up space from the origin to the end. Thus, it reduces
// the usable space for following layouts at it's origin by its // the usable space for following layouts at it's origin by its
// extent along the secondary axis. // extent along the secondary axis.
*bound.get_mut(*axes, GenericAxisKind::Secondary, Alignment::Origin) *bound.get_mut(*axes, Secondary, Origin)
+= axes.secondary.factor() * layout.dimensions.secondary(*axes); += axes.secondary.factor() * layout.dimensions.get_secondary(*axes);
} }
// ------------------------------------------------------------------ // // ------------------------------------------------------------------ //
@ -315,7 +315,7 @@ impl StackLayouter {
// The `x` field stores the maximal primary extent in one axis-aligned // The `x` field stores the maximal primary extent in one axis-aligned
// run, while the `y` fields stores the accumulated secondary extent. // run, while the `y` fields stores the accumulated secondary extent.
let mut extent = Size2D::ZERO; let mut extent = Size2D::ZERO;
let mut rotated = false; let mut rotation = Vertical;
for (bound, entry) in bounds.iter_mut().zip(&self.space.layouts).rev() { for (bound, entry) in bounds.iter_mut().zip(&self.space.layouts).rev() {
let (axes, layout) = entry; let (axes, layout) = entry;
@ -324,17 +324,16 @@ impl StackLayouter {
// (`extent.x`) dictates how much secondary extent the whole run // (`extent.x`) dictates how much secondary extent the whole run
// had. This value is thus stored in `extent.y`. The primary extent // had. This value is thus stored in `extent.y`. The primary extent
// is reset for this new axis-aligned run. // is reset for this new axis-aligned run.
let is_horizontal = axes.secondary.is_horizontal(); if rotation != axes.secondary.axis() {
if is_horizontal != rotated {
extent.y = extent.x; extent.y = extent.x;
extent.x = Size::ZERO; extent.x = Size::ZERO;
rotated = is_horizontal; rotation = axes.secondary.axis();
} }
// We reduce the bounding box of this layout at it's end by the // We reduce the bounding box of this layout at it's end by the
// accumulated secondary extent of all layouts we have seen so far, // accumulated secondary extent of all layouts we have seen so far,
// which are the layouts after this one since we iterate reversed. // which are the layouts after this one since we iterate reversed.
*bound.get_mut(*axes, GenericAxisKind::Secondary, Alignment::End) *bound.get_mut(*axes, Secondary, End)
-= axes.secondary.factor() * extent.y; -= axes.secondary.factor() * extent.y;
// Then, we add this layout's secondary extent to the accumulator. // Then, we add this layout's secondary extent to the accumulator.
@ -404,10 +403,10 @@ impl Space {
usable, usable,
extra: Size2D::ZERO, extra: Size2D::ZERO,
rulers: Rulers { rulers: Rulers {
top: Alignment::Origin, top: Origin,
bottom: Alignment::Origin, bottom: Origin,
left: Alignment::Origin, left: Origin,
right: Alignment::Origin, right: Origin,
}, },
last_spacing: LastSpacing::Hard, last_spacing: LastSpacing::Hard,
} }
@ -415,12 +414,12 @@ impl Space {
} }
impl Rulers { impl Rulers {
fn get(&mut self, axis: Axis) -> &mut Alignment { fn get(&mut self, direction: Direction) -> &mut Alignment {
match axis { match direction {
Axis::TopToBottom => &mut self.top, TopToBottom => &mut self.top,
Axis::BottomToTop => &mut self.bottom, BottomToTop => &mut self.bottom,
Axis::LeftToRight => &mut self.left, LeftToRight => &mut self.left,
Axis::RightToLeft => &mut self.right, RightToLeft => &mut self.right,
} }
} }
} }

View File

@ -76,13 +76,10 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
} }
fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> { fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> {
let spaces = self.stack.remaining();
let commands = func.0.layout(LayoutContext { let commands = func.0.layout(LayoutContext {
loader: self.ctx.loader,
style: &self.style, style: &self.style,
spaces, spaces: self.stack.remaining(),
top_level: false, nested: true,
debug: true, debug: true,
.. self.ctx .. self.ctx
})?; })?;
@ -103,8 +100,8 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
Add(layout) => self.stack.add(layout)?, Add(layout) => self.stack.add(layout)?,
AddMultiple(layouts) => self.stack.add_multiple(layouts)?, AddMultiple(layouts) => self.stack.add_multiple(layouts)?,
AddSpacing(space, kind, axis) => match axis { AddSpacing(space, kind, axis) => match axis {
GenericAxisKind::Primary => {}, Primary => {},
GenericAxisKind::Secondary => self.stack.add_spacing(space, kind), Secondary => self.stack.add_spacing(space, kind),
} }
FinishLine => {}, FinishLine => {},
@ -114,8 +111,8 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
SetTextStyle(style) => self.style.text = style, SetTextStyle(style) => self.style.text = style,
SetPageStyle(style) => { SetPageStyle(style) => {
if !self.ctx.top_level { if self.ctx.nested {
error!("the page style cannot only be altered from a top-level context"); error!("page style cannot be altered in nested context");
} }
self.style.page = style; self.style.page = style;
@ -123,7 +120,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
LayoutSpace { LayoutSpace {
dimensions: style.dimensions, dimensions: style.dimensions,
padding: style.margins, padding: style.margins,
expand: LayoutExpansion::new(true, true), expansion: LayoutExpansion::new(true, true),
} }
], true); ], true);
} }

View File

@ -91,6 +91,7 @@ impl<'p> Typesetter<'p> {
/// Layout a syntax tree and return the produced layout. /// Layout a syntax tree and return the produced layout.
pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<MultiLayout> { pub fn layout(&self, tree: &SyntaxTree) -> LayoutResult<MultiLayout> {
use crate::layout::prelude::*;
Ok(layout_tree( Ok(layout_tree(
&tree, &tree,
LayoutContext { LayoutContext {
@ -98,12 +99,13 @@ impl<'p> Typesetter<'p> {
style: &self.style, style: &self.style,
spaces: smallvec![LayoutSpace { spaces: smallvec![LayoutSpace {
dimensions: self.style.page.dimensions, dimensions: self.style.page.dimensions,
expand: LayoutExpansion::new(true, true),
padding: self.style.page.margins, padding: self.style.page.margins,
expansion: LayoutExpansion::new(true, true),
}], }],
axes: LayoutAxes::default(), repeat: true,
alignment: LayoutAlignment::default(), axes: LayoutAxes::new(LeftToRight, TopToBottom),
top_level: true, alignment: LayoutAlignment::new(Origin, Origin),
nested: false,
debug: false, debug: false,
}, },
)?) )?)

View File

@ -34,20 +34,20 @@ function! {
let map = self.map.dedup(|key, alignment| { let map = self.map.dedup(|key, alignment| {
let axis = match key { let axis = match key {
Key::First => alignment.axis(axes, GenericAxisKind::Primary), Key::First => alignment.axis(axes, Primary),
Key::Second => alignment.axis(axes, GenericAxisKind::Secondary), Key::Second => alignment.axis(axes, Secondary),
Key::Axis(AxisKey::Primary) => GenericAxisKind::Primary, Key::Axis(AxisKey::Primary) => Primary,
Key::Axis(AxisKey::Secondary) => GenericAxisKind::Secondary, Key::Axis(AxisKey::Secondary) => Secondary,
Key::Axis(AxisKey::Horizontal) => axes.horizontal(), Key::Axis(AxisKey::Horizontal) => Horizontal.to_generic(axes),
Key::Axis(AxisKey::Vertical) => axes.vertical(), Key::Axis(AxisKey::Vertical) => Vertical.to_generic(axes),
}; };
let alignment = alignment.generic(axes, axis)?; let alignment = alignment.to_generic(axes, axis)?;
Ok((axis, alignment)) Ok((axis, alignment))
})?; })?;
map.with(GenericAxisKind::Primary, |&val| ctx.alignment.primary = val); map.with(Primary, |&val| ctx.alignment.primary = val);
map.with(GenericAxisKind::Secondary, |&val| ctx.alignment.secondary = val); map.with(Secondary, |&val| ctx.alignment.secondary = val);
match &self.body { match &self.body {
Some(body) => vec![AddMultiple(layout_tree(&body, ctx)?)], Some(body) => vec![AddMultiple(layout_tree(&body, ctx)?)],

View File

@ -21,15 +21,13 @@ function! {
} }
layout(self, mut ctx) { layout(self, mut ctx) {
use SpecificAxisKind::*;
ctx.debug = self.debug; ctx.debug = self.debug;
let space = &mut ctx.spaces[0]; let space = &mut ctx.spaces[0];
self.map.apply_with(ctx.axes, |axis, p| { self.map.apply_with(ctx.axes, |axis, p| {
let entity = match axis { let entity = match axis {
Horizontal => { space.expand.horizontal = true; &mut space.dimensions.x }, Horizontal => { space.expansion.horizontal = true; &mut space.dimensions.x },
Vertical => { space.expand.vertical = true; &mut space.dimensions.y }, Vertical => { space.expansion.vertical = true; &mut space.dimensions.y },
}; };
*entity = p.concretize(*entity) *entity = p.concretize(*entity)

View File

@ -5,25 +5,25 @@ use super::keys::AxisKey;
function! { function! {
/// `direction`: Sets the directions of the layouting axes. /// `direction`: Sets the directions of the layouting axes.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Direction { pub struct DirectionChange {
body: Option<SyntaxTree>, body: Option<SyntaxTree>,
map: ConsistentMap<AxisKey, Axis>, map: ConsistentMap<AxisKey, Direction>,
} }
parse(args, body, ctx) { parse(args, body, ctx) {
let mut map = ConsistentMap::new(); let mut map = ConsistentMap::new();
map.add_opt_span(AxisKey::Primary, args.get_pos_opt::<Axis>()?)?; map.add_opt_span(AxisKey::Primary, args.get_pos_opt::<Direction>()?)?;
map.add_opt_span(AxisKey::Secondary, args.get_pos_opt::<Axis>()?)?; map.add_opt_span(AxisKey::Secondary, args.get_pos_opt::<Direction>()?)?;
for arg in args.keys() { for arg in args.keys() {
let axis = AxisKey::from_ident(&arg.v.key)?; let axis = AxisKey::from_ident(&arg.v.key)?;
let value = Axis::from_expr(arg.v.value)?; let value = Direction::from_expr(arg.v.value)?;
map.add(axis, value)?; map.add(axis, value)?;
} }
Direction { DirectionChange {
body: parse!(optional: body, ctx), body: parse!(optional: body, ctx),
map, map,
} }
@ -34,17 +34,17 @@ function! {
let map = self.map.dedup(|key, &direction| { let map = self.map.dedup(|key, &direction| {
Ok((match key { Ok((match key {
AxisKey::Primary => GenericAxisKind::Primary, AxisKey::Primary => Primary,
AxisKey::Secondary => GenericAxisKind::Secondary, AxisKey::Secondary => Secondary,
AxisKey::Horizontal => axes.horizontal(), AxisKey::Horizontal => Horizontal.to_generic(axes),
AxisKey::Vertical => axes.vertical(), AxisKey::Vertical => Vertical.to_generic(axes),
}, direction)) }, direction))
})?; })?;
map.with(GenericAxisKind::Primary, |&val| ctx.axes.primary = val); map.with(Primary, |&val| ctx.axes.primary = val);
map.with(GenericAxisKind::Secondary, |&val| ctx.axes.secondary = val); map.with(Secondary, |&val| ctx.axes.secondary = val);
if ctx.axes.primary.is_horizontal() == ctx.axes.secondary.is_horizontal() { if ctx.axes.primary.axis() == ctx.axes.secondary.axis() {
error!( error!(
"aligned primary and secondary axes: `{}`, `{}`", "aligned primary and secondary axes: `{}`, `{}`",
format!("{:?}", ctx.axes.primary).to_lowercase(), format!("{:?}", ctx.axes.primary).to_lowercase(),

View File

@ -39,33 +39,26 @@ pub enum AxisKey {
impl AxisKey { impl AxisKey {
/// The generic version of this axis key in the given system of axes. /// The generic version of this axis key in the given system of axes.
pub fn generic(&self, axes: LayoutAxes) -> GenericAxisKind { pub fn to_generic(self, axes: LayoutAxes) -> GenericAxis {
match self { match self {
AxisKey::Primary => GenericAxisKind::Primary, AxisKey::Primary => Primary,
AxisKey::Secondary => GenericAxisKind::Secondary, AxisKey::Secondary => Secondary,
AxisKey::Vertical => axes.vertical(), AxisKey::Vertical => Vertical.to_generic(axes),
AxisKey::Horizontal => axes.horizontal(), AxisKey::Horizontal => Horizontal.to_generic(axes),
} }
} }
/// The specific version of this axis key in the given system of axes. /// The specific version of this axis key in the given system of axes.
pub fn specific(&self, axes: LayoutAxes) -> SpecificAxisKind { pub fn to_specific(self, axes: LayoutAxes) -> SpecificAxis {
match self { match self {
AxisKey::Primary => axes.primary(), AxisKey::Primary => Primary.to_specific(axes),
AxisKey::Secondary => axes.secondary(), AxisKey::Secondary => Secondary.to_specific(axes),
AxisKey::Vertical => SpecificAxisKind::Vertical, AxisKey::Vertical => Vertical,
AxisKey::Horizontal => SpecificAxisKind::Horizontal, AxisKey::Horizontal => Horizontal,
} }
} }
} }
kind!(AxisKey, "axis",
"horizontal" => AxisKey::Horizontal,
"vertical" => AxisKey::Vertical,
"primary" => AxisKey::Primary,
"secondary" => AxisKey::Secondary,
);
/// An argument key which describes a target alignment. /// An argument key which describes a target alignment.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AlignmentKey { pub enum AlignmentKey {
@ -81,29 +74,35 @@ pub enum AlignmentKey {
impl AlignmentKey { impl AlignmentKey {
/// The generic axis this alignment key corresopnds to in the given system /// The generic axis this alignment key corresopnds to in the given system
/// of layouting axes. Falls back to `default` if the alignment is generic. /// of layouting axes. Falls back to `default` if the alignment is generic.
pub fn axis(&self, axes: LayoutAxes, default: GenericAxisKind) -> GenericAxisKind { pub fn axis(self, axes: LayoutAxes, default: GenericAxis) -> GenericAxis {
use AlignmentKey::*; use AlignmentKey::*;
match self { match self {
Origin | Center | End => default, Origin | Center | End => default,
Left | Right => axes.horizontal(), Left | Right => Horizontal.to_generic(axes),
Top | Bottom => axes.vertical(), Top | Bottom => Vertical.to_generic(axes),
} }
} }
/// The generic version of this alignment in the given system of layouting /// The generic version of this alignment in the given system of layouting
/// axes. Returns an error if the alignment is invalid for the given axis. /// axes.
pub fn generic(&self, axes: LayoutAxes, axis: GenericAxisKind) -> LayoutResult<Alignment> { ///
use AlignmentKey::*; /// Returns an error if the alignment is invalid for the given axis.
pub fn to_generic(self, axes: LayoutAxes, axis: GenericAxis) -> LayoutResult<Alignment> {
let specific = axis.to_specific(axes);
Ok(match (self, specific) {
(AlignmentKey::Origin, _) => Origin,
(AlignmentKey::Center, _) => Center,
(AlignmentKey::End, _) => End,
(AlignmentKey::Left, Horizontal) | (AlignmentKey::Top, Vertical) => {
if axes.get_specific(specific).is_positive() { Origin } else { End }
}
(AlignmentKey::Right, Horizontal) | (AlignmentKey::Bottom, Vertical) => {
if axes.get_specific(specific).is_positive() { End } else { Origin }
}
let horizontal = axis == axes.horizontal();
Ok(match self {
Origin => Alignment::Origin,
Center => Alignment::Center,
End => Alignment::End,
Left if horizontal => axes.left(),
Right if horizontal => axes.right(),
Top if !horizontal => axes.top(),
Bottom if !horizontal => axes.bottom(),
_ => error!( _ => error!(
"invalid alignment `{}` for {} axis", "invalid alignment `{}` for {} axis",
format!("{:?}", self).to_lowercase(), format!("{:?}", self).to_lowercase(),
@ -114,31 +113,20 @@ impl AlignmentKey {
/// The specific version of this alignment in the given system of layouting /// The specific version of this alignment in the given system of layouting
/// axes. /// axes.
pub fn specific(&self, axes: LayoutAxes, axis: SpecificAxisKind) -> AlignmentKey { pub fn to_specific(self, axes: LayoutAxes, axis: SpecificAxis) -> AlignmentKey {
use AlignmentKey::*; use AlignmentKey::*;
use SpecificAxisKind::*;
let positive = axes.specific(axis).is_positive(); let positive = axes.get_specific(axis).is_positive();
match (self, axis, positive) { match (self, axis, positive) {
(Origin, Horizontal, true) | (End, Horizontal, false) => Left, (Origin, Horizontal, true) | (End, Horizontal, false) => Left,
(End, Horizontal, true) | (Origin, Horizontal, false) => Right, (End, Horizontal, true) | (Origin, Horizontal, false) => Right,
(Origin, Vertical, true) | (End, Vertical, false) => Top, (Origin, Vertical, true) | (End, Vertical, false) => Top,
(End, Vertical, true) | (Origin, Vertical, false) => Bottom, (End, Vertical, true) | (Origin, Vertical, false) => Bottom,
_ => *self, _ => self,
} }
} }
} }
kind!(AlignmentKey, "alignment",
"left" => AlignmentKey::Left,
"top" => AlignmentKey::Top,
"right" => AlignmentKey::Right,
"bottom" => AlignmentKey::Bottom,
"origin" => AlignmentKey::Origin,
"center" => AlignmentKey::Center,
"end" => AlignmentKey::End,
);
/// An argument key which identifies a margin or padding target. /// An argument key which identifies a margin or padding target.
/// ///
/// A is the used axis type. /// A is the used axis type.
@ -152,30 +140,47 @@ pub enum PaddingKey<A> {
AxisAligned(A, AlignmentKey), AxisAligned(A, AlignmentKey),
} }
kind!(AxisKey, "axis",
"horizontal" | "h" => AxisKey::Horizontal,
"vertical" | "v" => AxisKey::Vertical,
"primary" | "p" => AxisKey::Primary,
"secondary" | "s" => AxisKey::Secondary,
);
kind!(AlignmentKey, "alignment",
"left" => AlignmentKey::Left,
"top" => AlignmentKey::Top,
"right" => AlignmentKey::Right,
"bottom" => AlignmentKey::Bottom,
"origin" => AlignmentKey::Origin,
"center" => AlignmentKey::Center,
"end" => AlignmentKey::End,
);
kind!(PaddingKey<AxisKey>, "axis or side", kind!(PaddingKey<AxisKey>, "axis or side",
"horizontal" => PaddingKey::Axis(AxisKey::Horizontal), "horizontal" | "h" => PaddingKey::Axis(AxisKey::Horizontal),
"vertical" => PaddingKey::Axis(AxisKey::Vertical), "vertical" | "v" => PaddingKey::Axis(AxisKey::Vertical),
"primary" => PaddingKey::Axis(AxisKey::Primary), "primary" | "p" => PaddingKey::Axis(AxisKey::Primary),
"secondary" => PaddingKey::Axis(AxisKey::Secondary), "secondary" | "s" => PaddingKey::Axis(AxisKey::Secondary),
"left" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Left), "left" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Left),
"right" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Right), "right" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Right),
"top" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Top), "top" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Top),
"bottom" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Bottom), "bottom" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Bottom),
"primary-origin" => PaddingKey::AxisAligned(AxisKey::Primary, AlignmentKey::Origin), "primary-origin" => PaddingKey::AxisAligned(AxisKey::Primary, AlignmentKey::Origin),
"primary-end" => PaddingKey::AxisAligned(AxisKey::Primary, AlignmentKey::End), "primary-end" => PaddingKey::AxisAligned(AxisKey::Primary, AlignmentKey::End),
"secondary-origin" => PaddingKey::AxisAligned(AxisKey::Secondary, AlignmentKey::Origin), "secondary-origin" => PaddingKey::AxisAligned(AxisKey::Secondary, AlignmentKey::Origin),
"secondary-end" => PaddingKey::AxisAligned(AxisKey::Secondary, AlignmentKey::End), "secondary-end" => PaddingKey::AxisAligned(AxisKey::Secondary, AlignmentKey::End),
"horizontal-origin" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Origin), "horizontal-origin" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::Origin),
"horizontal-end" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::End), "horizontal-end" => PaddingKey::AxisAligned(AxisKey::Horizontal, AlignmentKey::End),
"vertical-origin" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Origin), "vertical-origin" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::Origin),
"vertical-end" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::End), "vertical-end" => PaddingKey::AxisAligned(AxisKey::Vertical, AlignmentKey::End),
); );
kind!(Axis, "direction", kind!(Direction, "direction",
"ltr" => Axis::LeftToRight, "left-to-right" | "ltr" => LeftToRight,
"rtl" => Axis::RightToLeft, "right-to-left" | "rtl" => RightToLeft,
"ttb" => Axis::TopToBottom, "top-to-bottom" | "ttb" => TopToBottom,
"btt" => Axis::BottomToTop, "bottom-to-top" | "btt" => BottomToTop,
); );

View File

@ -84,10 +84,11 @@ impl<E: ExpressionKind + Copy> ExtentMap<E> {
for arg in args.keys() { for arg in args.keys() {
let key = match arg.v.key.v.0.as_str() { let key = match arg.v.key.v.0.as_str() {
"width" | "w" => AxisKey::Horizontal, "width" | "w" => AxisKey::Horizontal,
"height" | "h" => AxisKey::Vertical, "height" | "h" => AxisKey::Vertical,
"primary-size" | "ps" => AxisKey::Primary, "primary-size" | "ps" => AxisKey::Primary,
"secondary-size" | "ss" => AxisKey::Secondary, "secondary-size" | "ss" => AxisKey::Secondary,
_ => if enforce { _ => if enforce {
error!("expected dimension") error!("expected dimension")
} else { } else {
@ -111,22 +112,22 @@ impl<E: ExpressionKind + Copy> ExtentMap<E> {
size: F size: F
) -> LayoutResult<()> where F: Fn(&E) -> Size { ) -> LayoutResult<()> where F: Fn(&E) -> Size {
let map = self.dedup(axes)?; let map = self.dedup(axes)?;
map.with(SpecificAxisKind::Horizontal, |val| dimensions.x = size(val)); map.with(Horizontal, |val| dimensions.x = size(val));
map.with(SpecificAxisKind::Vertical, |val| dimensions.y = size(val)); map.with(Vertical, |val| dimensions.y = size(val));
Ok(()) Ok(())
} }
/// Map from any axis key to the specific axis kind. /// Map from any axis key to the specific axis kind.
pub fn apply_with<F>(&self, axes: LayoutAxes, mut f: F) -> LayoutResult<()> pub fn apply_with<F>(&self, axes: LayoutAxes, mut f: F) -> LayoutResult<()>
where F: FnMut(SpecificAxisKind, &E) { where F: FnMut(SpecificAxis, &E) {
for (&key, value) in self.dedup(axes)?.iter() { for (&key, value) in self.dedup(axes)?.iter() {
f(key, value); f(key, value);
} }
Ok(()) Ok(())
} }
fn dedup(&self, axes: LayoutAxes) -> LayoutResult<ConsistentMap<SpecificAxisKind, E>> { fn dedup(&self, axes: LayoutAxes) -> LayoutResult<ConsistentMap<SpecificAxis, E>> {
self.0.dedup(|key, &val| Ok((key.specific(axes), val))) self.0.dedup(|key, &val| Ok((key.to_specific(axes), val)))
} }
} }
@ -165,17 +166,17 @@ impl PaddingMap {
let map = self.0.dedup(|key, &val| { let map = self.0.dedup(|key, &val| {
Ok((match key { Ok((match key {
All => All, All => All,
Axis(axis) => Axis(axis.specific(axes)), Axis(axis) => Axis(axis.to_specific(axes)),
AxisAligned(axis, alignment) => { AxisAligned(axis, alignment) => {
let axis = axis.specific(axes); let axis = axis.to_specific(axes);
AxisAligned(axis, alignment.specific(axes, axis)) AxisAligned(axis, alignment.to_specific(axes, axis))
} }
}, val)) }, val))
})?; })?;
map.with(All, |&val| padding.set_all(val)); map.with(All, |&val| padding.set_all(val));
map.with(Axis(SpecificAxisKind::Horizontal), |&val| padding.set_horizontal(val)); map.with(Axis(Horizontal), |&val| padding.set_horizontal(val));
map.with(Axis(SpecificAxisKind::Vertical), |&val| padding.set_vertical(val)); map.with(Axis(Vertical), |&val| padding.set_vertical(val));
for (key, &val) in map.iter() { for (key, &val) in map.iter() {
if let AxisAligned(_, alignment) = key { if let AxisAligned(_, alignment) = key {

View File

@ -19,7 +19,7 @@ pub fn std() -> Scope {
std.add::<Align>("align"); std.add::<Align>("align");
std.add::<Boxed>("box"); std.add::<Boxed>("box");
std.add::<Direction>("direction"); std.add::<DirectionChange>("direction");
std.add::<PageSize>("page.size"); std.add::<PageSize>("page.size");
std.add::<PageMargins>("page.margins"); std.add::<PageMargins>("page.margins");
@ -30,10 +30,10 @@ pub fn std() -> Scope {
std.add::<FontSize>("font.size"); std.add::<FontSize>("font.size");
std.add_with_metadata::<Spacing, Option<AxisKey>>("spacing", None); std.add_with_metadata::<Spacing>("spacing", None);
for (name, key) in &[("h", AxisKey::Horizontal), ("v", AxisKey::Vertical)] { for (name, key) in &[("h", AxisKey::Horizontal), ("v", AxisKey::Vertical)] {
std.add_with_metadata::<Spacing, Option<AxisKey>>(name, Some(*key)); std.add_with_metadata::<Spacing>(name, Some(*key));
} }
for (name, class) in &[ for (name, class) in &[
@ -41,7 +41,7 @@ pub fn std() -> Scope {
("italic", FontClass::Italic), ("italic", FontClass::Italic),
("mono", FontClass::Monospace), ("mono", FontClass::Monospace),
] { ] {
std.add_with_metadata::<StyleChange, FontClass>(name, class.clone()); std.add_with_metadata::<StyleChange>(name, class.clone());
} }
std std
@ -152,7 +152,7 @@ function! {
} }
layout(self, ctx) { layout(self, ctx) {
let axis = self.axis.generic(ctx.axes); let axis = self.axis.to_generic(ctx.axes);
let spacing = self.spacing.concretize(ctx.style.text.font_size); let spacing = self.spacing.concretize(ctx.style.text.font_size);
vec![AddSpacing(spacing, SpacingKind::Hard, axis)] vec![AddSpacing(spacing, SpacingKind::Hard, axis)]
} }

View File

@ -5,8 +5,7 @@ use std::iter::Sum;
use std::ops::*; use std::ops::*;
use std::str::FromStr; use std::str::FromStr;
use crate::layout::{LayoutAxes, Axis, GenericAxisKind, LayoutAlignment, Alignment}; use crate::layout::prelude::*;
/// A general spacing type. /// A general spacing type.
#[derive(Copy, Clone, PartialEq, PartialOrd)] #[derive(Copy, Clone, PartialEq, PartialOrd)]
@ -59,11 +58,10 @@ impl Size {
/// Set this size to the minimum of itself and the other size. /// Set this size to the minimum of itself and the other size.
pub fn min_eq(&mut self, other: Size) { *self = self.min(other); } pub fn min_eq(&mut self, other: Size) { *self = self.min(other); }
/// The anchor position along the given axis for an item with the given /// The anchor position along the given direction for an item with the given
/// alignment in a container with this size. /// alignment in a container with this size.
pub fn anchor(self, alignment: Alignment, axis: Axis) -> Size { pub fn anchor(self, alignment: Alignment, direction: Direction) -> Size {
use Alignment::*; match (direction.is_positive(), alignment) {
match (axis.is_positive(), alignment) {
(true, Origin) | (false, End) => Size::ZERO, (true, Origin) | (false, End) => Size::ZERO,
(_, Center) => self / 2, (_, Center) => self / 2,
(true, End) | (false, Origin) => self, (true, End) | (false, Origin) => self,
@ -120,23 +118,23 @@ impl Size2D {
pub fn with_all(s: Size) -> Size2D { Size2D { x: s, y: s } } pub fn with_all(s: Size) -> Size2D { Size2D { x: s, y: s } }
/// Access the primary size of this specialized 2D-size. /// Access the primary size of this specialized 2D-size.
pub fn primary(self, axes: LayoutAxes) -> Size { pub fn get_primary(self, axes: LayoutAxes) -> Size {
if axes.primary.is_horizontal() { self.x } else { self.y } if axes.primary.axis() == Horizontal { self.x } else { self.y }
} }
/// Access the primary size of this specialized 2D-size mutably. /// Access the primary size of this specialized 2D-size mutably.
pub fn primary_mut(&mut self, axes: LayoutAxes) -> &mut Size { pub fn get_primary_mut(&mut self, axes: LayoutAxes) -> &mut Size {
if axes.primary.is_horizontal() { &mut self.x } else { &mut self.y } if axes.primary.axis() == Horizontal { &mut self.x } else { &mut self.y }
} }
/// Access the secondary size of this specialized 2D-size. /// Access the secondary size of this specialized 2D-size.
pub fn secondary(self, axes: LayoutAxes) -> Size { pub fn get_secondary(self, axes: LayoutAxes) -> Size {
if axes.primary.is_horizontal() { self.y } else { self.x } if axes.primary.axis() == Horizontal { self.y } else { self.x }
} }
/// Access the secondary size of this specialized 2D-size mutably. /// Access the secondary size of this specialized 2D-size mutably.
pub fn secondary_mut(&mut self, axes: LayoutAxes) -> &mut Size { pub fn get_secondary_mut(&mut self, axes: LayoutAxes) -> &mut Size {
if axes.primary.is_horizontal() { &mut self.y } else { &mut self.x } if axes.primary.axis() == Horizontal { &mut self.y } else { &mut self.x }
} }
/// Returns the generalized version of a `Size2D` dependent on the layouting /// Returns the generalized version of a `Size2D` dependent on the layouting
@ -144,9 +142,9 @@ impl Size2D {
/// - `x` describes the primary axis instead of the horizontal one. /// - `x` describes the primary axis instead of the horizontal one.
/// - `y` describes the secondary axis instead of the vertical one. /// - `y` describes the secondary axis instead of the vertical one.
pub fn generalized(self, axes: LayoutAxes) -> Size2D { pub fn generalized(self, axes: LayoutAxes) -> Size2D {
match axes.primary.is_horizontal() { match axes.primary.axis() {
true => self, Horizontal => self,
false => Size2D { x: self.y, y: self.x }, Vertical => Size2D { x: self.y, y: self.x },
} }
} }
@ -249,19 +247,19 @@ impl SizeBox {
/// alignment. /// alignment.
pub fn get_mut(&mut self, pub fn get_mut(&mut self,
axes: LayoutAxes, axes: LayoutAxes,
axis: GenericAxisKind, axis: GenericAxis,
alignment: Alignment, alignment: Alignment,
) -> &mut Size { ) -> &mut Size {
let mut normalized = axes.generic(axis); let mut normalized = axes.get_generic(axis);
if alignment == Alignment::End { if alignment == End {
normalized = normalized.inv(); normalized = normalized.inv();
} }
match normalized { match normalized {
Axis::LeftToRight => &mut self.left, LeftToRight => &mut self.left,
Axis::RightToLeft => &mut self.right, RightToLeft => &mut self.right,
Axis::TopToBottom => &mut self.top, TopToBottom => &mut self.top,
Axis::BottomToTop => &mut self.bottom, BottomToTop => &mut self.bottom,
} }
} }