mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Specify both axis with align function ➕
This commit is contained in:
parent
ebff8eb038
commit
4ab7ec6a9a
@ -324,6 +324,8 @@ impl SpaceState {
|
|||||||
pub enum LayoutError {
|
pub enum LayoutError {
|
||||||
/// An action is unallowed in the active context.
|
/// An action is unallowed in the active context.
|
||||||
Unallowed(&'static str),
|
Unallowed(&'static str),
|
||||||
|
/// A specifier or operation is invalid for the given axis.
|
||||||
|
UnalignedAxis(&'static str),
|
||||||
/// There is not enough space to add an item.
|
/// There is not enough space to add an item.
|
||||||
NotEnoughSpace(&'static str),
|
NotEnoughSpace(&'static str),
|
||||||
/// There was no suitable font for the given character.
|
/// There was no suitable font for the given character.
|
||||||
@ -339,6 +341,7 @@ error_type! {
|
|||||||
err: LayoutError,
|
err: LayoutError,
|
||||||
show: f => match err {
|
show: f => match err {
|
||||||
LayoutError::Unallowed(desc) => write!(f, "unallowed: {}", desc),
|
LayoutError::Unallowed(desc) => write!(f, "unallowed: {}", desc),
|
||||||
|
LayoutError::UnalignedAxis(desc) => write!(f, "unaligned axis: {}", desc),
|
||||||
LayoutError::NotEnoughSpace(desc) => write!(f, "not enough space: {}", desc),
|
LayoutError::NotEnoughSpace(desc) => write!(f, "not enough space: {}", desc),
|
||||||
LayoutError::NoSuitableFont(c) => write!(f, "no suitable font for '{}'", c),
|
LayoutError::NoSuitableFont(c) => write!(f, "no suitable font for '{}'", c),
|
||||||
LayoutError::Font(err) => write!(f, "font error: {}", err),
|
LayoutError::Font(err) => write!(f, "font error: {}", err),
|
||||||
|
@ -4,7 +4,21 @@ use crate::func::prelude::*;
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Align {
|
pub struct Align {
|
||||||
body: Option<SyntaxTree>,
|
body: Option<SyntaxTree>,
|
||||||
alignment: Alignment,
|
primary: Option<AlignSpecifier>,
|
||||||
|
secondary: Option<AlignSpecifier>,
|
||||||
|
horizontal: Option<AlignSpecifier>,
|
||||||
|
vertical: Option<AlignSpecifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
enum AlignSpecifier {
|
||||||
|
Origin,
|
||||||
|
Center,
|
||||||
|
End,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
@ -12,29 +26,76 @@ function! {
|
|||||||
|
|
||||||
parse(args, body, ctx) {
|
parse(args, body, ctx) {
|
||||||
let body = parse!(optional: body, ctx);
|
let body = parse!(optional: body, ctx);
|
||||||
let arg = args.get_pos::<ArgIdent>()?;
|
|
||||||
let alignment = match arg.val {
|
let mut align = Align {
|
||||||
"left" | "origin" => Alignment::Origin,
|
body,
|
||||||
"center" => Alignment::Center,
|
primary: None,
|
||||||
"right" | "end" => Alignment::End,
|
secondary: None,
|
||||||
s => err!("invalid alignment specifier: {}", s),
|
horizontal: None,
|
||||||
|
vertical: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(arg) = args.get_pos_opt::<ArgIdent>()? {
|
||||||
|
align.primary = Some(parse_align_specifier(arg)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut parse_arg = |axis, target: &mut Option<AlignSpecifier>| {
|
||||||
|
Ok(if let Some(arg) = args.get_key_opt::<ArgIdent>(axis)? {
|
||||||
|
if target.is_none() {
|
||||||
|
*target = Some(parse_align_specifier(arg)?);
|
||||||
|
} else {
|
||||||
|
err!("duplicate alignment specification for {} axis", axis);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
parse_arg("primary", &mut align.primary)?;
|
||||||
|
parse_arg("secondary", &mut align.secondary)?;
|
||||||
|
parse_arg("horizontal", &mut align.horizontal)?;
|
||||||
|
parse_arg("vertical", &mut align.vertical)?;
|
||||||
|
|
||||||
args.done()?;
|
args.done()?;
|
||||||
|
|
||||||
Ok(Align {
|
Ok(align)
|
||||||
body,
|
|
||||||
alignment,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layout(this, ctx) {
|
layout(this, ctx) {
|
||||||
let mut axes = ctx.axes;
|
let mut axes = ctx.axes;
|
||||||
axes.primary.alignment = this.alignment;
|
let primary_horizontal = axes.primary.axis.is_horizontal();
|
||||||
|
|
||||||
if ctx.axes.primary.alignment == Alignment::End
|
let mut primary = false;
|
||||||
&& this.alignment == Alignment::Origin {
|
let mut secondary = false;
|
||||||
axes.primary.expand = true;
|
|
||||||
}
|
let mut set_axis = |is_primary: bool, spec: Option<AlignSpecifier>| -> LayoutResult<()> {
|
||||||
|
if let Some(spec) = spec {
|
||||||
|
let (axis, was_set, name) = match is_primary {
|
||||||
|
true => (&mut axes.primary, &mut primary, "primary"),
|
||||||
|
false => (&mut axes.secondary, &mut secondary, "secondary"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if *was_set {
|
||||||
|
panic!("duplicate alignment for {} axis", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
*was_set = true;
|
||||||
|
|
||||||
|
let horizontal = axis.axis.is_horizontal();
|
||||||
|
let alignment = generic_alignment(spec, horizontal)?;
|
||||||
|
|
||||||
|
if axis.alignment == Alignment::End && alignment == Alignment::Origin {
|
||||||
|
axis.expand = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
axis.alignment = alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
set_axis(true, this.primary)?;
|
||||||
|
set_axis(false, this.secondary)?;
|
||||||
|
set_axis(primary_horizontal, this.horizontal)?;
|
||||||
|
set_axis(!primary_horizontal, this.vertical)?;
|
||||||
|
|
||||||
Ok(match &this.body {
|
Ok(match &this.body {
|
||||||
Some(body) => commands![AddMultiple(
|
Some(body) => commands![AddMultiple(
|
||||||
@ -47,3 +108,26 @@ function! {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_align_specifier(arg: Spanned<&str>) -> ParseResult<AlignSpecifier> {
|
||||||
|
Ok(match arg.val {
|
||||||
|
"origin" => AlignSpecifier::Origin,
|
||||||
|
"center" => AlignSpecifier::Center,
|
||||||
|
"end" => AlignSpecifier::End,
|
||||||
|
"left" => AlignSpecifier::Left,
|
||||||
|
"right" => AlignSpecifier::Right,
|
||||||
|
"top" => AlignSpecifier::Top,
|
||||||
|
"bottom" => AlignSpecifier::Bottom,
|
||||||
|
s => err!("invalid alignment specifier: {}", s),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generic_alignment(spec: AlignSpecifier, horizontal: bool) -> LayoutResult<Alignment> {
|
||||||
|
use AlignSpecifier::*;
|
||||||
|
Ok(match (spec, horizontal) {
|
||||||
|
(Origin, _) | (Left, true) | (Top, false) => Alignment::Origin,
|
||||||
|
(Center, _) => Alignment::Center,
|
||||||
|
(End, _) | (Right, true) | (Bottom, false) => Alignment::End,
|
||||||
|
_ => Err(LayoutError::UnalignedAxis("invalid alignment"))?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user