diff options
Diffstat (limited to 'src/library/align.rs')
| -rw-r--r-- | src/library/align.rs | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index acd3a85c..d6b14692 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use std::fmt::{self, Display, Formatter}; /// `align`: Align content along the layouting axes. /// @@ -18,10 +19,10 @@ pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value { let snapshot = ctx.state.clone(); let body = args.find::<SynTree>(); - let first = args.get::<_, Spanned<SpecAlign>>(ctx, 0); - let second = args.get::<_, Spanned<SpecAlign>>(ctx, 1); - let hor = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal"); - let ver = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical"); + let first = args.get::<_, Spanned<AlignArg>>(ctx, 0); + let second = args.get::<_, Spanned<AlignArg>>(ctx, 1); + let hor = args.get::<_, Spanned<AlignArg>>(ctx, "horizontal"); + let ver = args.get::<_, Spanned<AlignArg>>(ctx, "vertical"); args.done(ctx); let iter = first @@ -50,10 +51,10 @@ pub fn align(mut args: Args, ctx: &mut EvalContext) -> Value { /// Deduplicate alignments and deduce to which axes they apply. fn dedup_aligns( ctx: &mut EvalContext, - iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<SpecAlign>)>, -) -> Gen2<GenAlign> { + iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<AlignArg>)>, +) -> Gen<Align> { let mut aligns = ctx.state.aligns; - let mut had = Gen2::new(false, false); + let mut had = Gen::new(false, false); let mut had_center = false; for (axis, Spanned { v: align, span }) in iter { @@ -77,15 +78,15 @@ fn dedup_aligns( } else { // We don't know the axis: This has to be a `center` alignment for a // positional argument. - debug_assert_eq!(align, SpecAlign::Center); + debug_assert_eq!(align, AlignArg::Center); if had.main && had.cross { ctx.diag(error!(span, "duplicate alignment")); } else if had_center { // Both this and the previous one are unspecified `center` // alignments. Both axes should be centered. - aligns = Gen2::new(GenAlign::Center, GenAlign::Center); - had = Gen2::new(true, true); + aligns = Gen::new(Align::Center, Align::Center); + had = Gen::new(true, true); } else { had_center = true; } @@ -95,10 +96,10 @@ fn dedup_aligns( // alignment. if had_center && (had.main || had.cross) { if had.main { - aligns.cross = GenAlign::Center; + aligns.cross = Align::Center; had.cross = true; } else { - aligns.main = GenAlign::Center; + aligns.main = Align::Center; had.main = true; } had_center = false; @@ -108,8 +109,77 @@ fn dedup_aligns( // If center has not been flushed by now, it is the only argument and then // we default to applying it to the cross axis. if had_center { - aligns.cross = GenAlign::Center; + aligns.cross = Align::Center; } aligns } + +/// An alignment argument. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] +enum AlignArg { + Left, + Right, + Top, + Bottom, + Center, +} + +impl AlignArg { + /// The specific axis this alignment refers to. + /// + /// Returns `None` if this is `Center` since the axis is unknown. + pub fn axis(self) -> Option<SpecAxis> { + match self { + Self::Left => Some(SpecAxis::Horizontal), + Self::Right => Some(SpecAxis::Horizontal), + Self::Top => Some(SpecAxis::Vertical), + Self::Bottom => Some(SpecAxis::Vertical), + Self::Center => None, + } + } +} + +impl Switch for AlignArg { + type Other = Align; + + fn switch(self, dirs: Gen<Dir>) -> Self::Other { + let get = |dir: Dir, at_positive_start| { + if dir.is_positive() == at_positive_start { + Align::Start + } else { + Align::End + } + }; + + let dirs = dirs.switch(dirs); + match self { + Self::Left => get(dirs.horizontal, true), + Self::Right => get(dirs.horizontal, false), + Self::Top => get(dirs.vertical, true), + Self::Bottom => get(dirs.vertical, false), + Self::Center => Align::Center, + } + } +} + +convert_ident!(AlignArg, "alignment", |v| match v { + "left" => Some(Self::Left), + "right" => Some(Self::Right), + "top" => Some(Self::Top), + "bottom" => Some(Self::Bottom), + "center" => Some(Self::Center), + _ => None, +}); + +impl Display for AlignArg { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad(match self { + Self::Left => "left", + Self::Right => "right", + Self::Top => "top", + Self::Bottom => "bottom", + Self::Center => "center", + }) + } +} |
