mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Fix secondary non-origin alignment 🚧
This commit is contained in:
parent
4ab7ec6a9a
commit
6ff60bc368
@ -14,7 +14,7 @@ pub struct FlexLayouter {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
enum FlexUnit {
|
enum FlexUnit {
|
||||||
Boxed(Layout),
|
Boxed(Layout),
|
||||||
Space(Size, bool),
|
Space(Size, SpaceKind),
|
||||||
SetAxes(LayoutAxes),
|
SetAxes(LayoutAxes),
|
||||||
Break,
|
Break,
|
||||||
}
|
}
|
||||||
@ -102,15 +102,15 @@ impl FlexLayouter {
|
|||||||
self.units.push(FlexUnit::Break);
|
self.units.push(FlexUnit::Break);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_primary_space(&mut self, space: Size, soft: bool) {
|
pub fn add_primary_space(&mut self, space: Size, kind: SpaceKind) {
|
||||||
self.units.push(FlexUnit::Space(space, soft))
|
self.units.push(FlexUnit::Space(space, kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_secondary_space(&mut self, space: Size, soft: bool) -> LayoutResult<()> {
|
pub fn add_secondary_space(&mut self, space: Size, kind: SpaceKind) -> LayoutResult<()> {
|
||||||
if !self.run_is_empty() {
|
if !self.run_is_empty() {
|
||||||
self.finish_run()?;
|
self.finish_run()?;
|
||||||
}
|
}
|
||||||
Ok(self.stack.add_space(space, soft))
|
Ok(self.stack.add_space(space, kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_axes(&mut self, axes: LayoutAxes) {
|
pub fn set_axes(&mut self, axes: LayoutAxes) {
|
||||||
@ -169,7 +169,7 @@ impl FlexLayouter {
|
|||||||
for unit in units {
|
for unit in units {
|
||||||
match unit {
|
match unit {
|
||||||
FlexUnit::Boxed(boxed) => self.layout_box(boxed)?,
|
FlexUnit::Boxed(boxed) => self.layout_box(boxed)?,
|
||||||
FlexUnit::Space(space, soft) => self.layout_space(space, soft),
|
FlexUnit::Space(space, kind) => self.layout_space(space, kind),
|
||||||
FlexUnit::SetAxes(axes) => self.layout_set_axes(axes),
|
FlexUnit::SetAxes(axes) => self.layout_set_axes(axes),
|
||||||
FlexUnit::Break => { self.finish_line()?; },
|
FlexUnit::Break => { self.finish_line()?; },
|
||||||
}
|
}
|
||||||
@ -186,13 +186,13 @@ impl FlexLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.stack.add(Layout {
|
self.stack.add(Layout {
|
||||||
dimensions: self.axes.specialize(
|
dimensions: self.axes.specialize(self.line.combined_dimensions),
|
||||||
self.line.combined_dimensions+ Size2D::with_y(self.flex_spacing)
|
|
||||||
),
|
|
||||||
actions: self.line.actions.to_vec(),
|
actions: self.line.actions.to_vec(),
|
||||||
debug_render: false,
|
debug_render: false,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
self.stack.add_space(self.flex_spacing, SpaceKind::Independent);
|
||||||
|
|
||||||
let remaining = self.axes.specialize(Size2D {
|
let remaining = self.axes.specialize(Size2D {
|
||||||
x: self.part.usable
|
x: self.part.usable
|
||||||
- self.part.dimensions.x
|
- self.part.dimensions.x
|
||||||
@ -250,7 +250,7 @@ impl FlexLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let SpaceState::Soft(space) = self.part.space {
|
if let SpaceState::Soft(space) = self.part.space {
|
||||||
self.layout_space(space, false);
|
self.layout_space(space, SpaceKind::Hard);
|
||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.part.dimensions.x;
|
let offset = self.part.dimensions.x;
|
||||||
@ -263,8 +263,8 @@ impl FlexLayouter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_space(&mut self, space: Size, soft: bool) {
|
fn layout_space(&mut self, space: Size, kind: SpaceKind) {
|
||||||
if soft {
|
if kind == SpaceKind::Soft {
|
||||||
if self.part.space != SpaceState::Forbidden {
|
if self.part.space != SpaceState::Forbidden {
|
||||||
self.part.space = SpaceState::Soft(space);
|
self.part.space = SpaceState::Soft(space);
|
||||||
}
|
}
|
||||||
@ -275,7 +275,9 @@ impl FlexLayouter {
|
|||||||
self.part.dimensions.x += space;
|
self.part.dimensions.x += space;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.part.space = SpaceState::Forbidden;
|
if kind == SpaceKind::Hard {
|
||||||
|
self.part.space = SpaceState::Forbidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +308,17 @@ pub enum Alignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum SpaceState {
|
pub enum SpaceKind {
|
||||||
|
/// Soft spaces are eaten up by hard spaces before or after them.
|
||||||
|
Soft,
|
||||||
|
/// Independent do not eat up soft spaces and are not eaten up by hard spaces.
|
||||||
|
Independent,
|
||||||
|
/// Hard spaces eat up soft spaces before or after them.
|
||||||
|
Hard,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
enum SpaceState {
|
||||||
Soft(Size),
|
Soft(Size),
|
||||||
Forbidden,
|
Forbidden,
|
||||||
Allowed,
|
Allowed,
|
||||||
|
@ -32,10 +32,14 @@ impl Space {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Subspace {
|
struct Subspace {
|
||||||
origin: Size2D,
|
origin: Size2D,
|
||||||
usable: Size2D,
|
|
||||||
anchor: Size2D,
|
anchor: Size2D,
|
||||||
factor: i32,
|
factor: i32,
|
||||||
|
|
||||||
|
boxes: Vec<(Size, Size, Layout)>,
|
||||||
|
|
||||||
|
usable: Size2D,
|
||||||
dimensions: Size2D,
|
dimensions: Size2D,
|
||||||
|
|
||||||
space: SpaceState,
|
space: SpaceState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +47,10 @@ impl Subspace {
|
|||||||
fn new(origin: Size2D, usable: Size2D, axes: LayoutAxes) -> Subspace {
|
fn new(origin: Size2D, usable: Size2D, axes: LayoutAxes) -> Subspace {
|
||||||
Subspace {
|
Subspace {
|
||||||
origin,
|
origin,
|
||||||
usable: axes.generalize(usable),
|
|
||||||
anchor: axes.anchor(usable),
|
anchor: axes.anchor(usable),
|
||||||
factor: axes.secondary.axis.factor(),
|
factor: axes.secondary.axis.factor(),
|
||||||
|
boxes: vec![],
|
||||||
|
usable: axes.generalize(usable),
|
||||||
dimensions: Size2D::zero(),
|
dimensions: Size2D::zero(),
|
||||||
space: SpaceState::Forbidden,
|
space: SpaceState::Forbidden,
|
||||||
}
|
}
|
||||||
@ -78,7 +83,7 @@ impl StackLayouter {
|
|||||||
|
|
||||||
pub fn add(&mut self, layout: Layout) -> LayoutResult<()> {
|
pub fn add(&mut self, layout: Layout) -> LayoutResult<()> {
|
||||||
if let SpaceState::Soft(space) = self.sub.space {
|
if let SpaceState::Soft(space) = self.sub.space {
|
||||||
self.add_space(space, false);
|
self.add_space(space, SpaceKind::Hard);
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = self.ctx.axes.generalize(layout.dimensions);
|
let size = self.ctx.axes.generalize(layout.dimensions);
|
||||||
@ -90,9 +95,6 @@ impl StackLayouter {
|
|||||||
|
|
||||||
while !self.sub.usable.fits(new_dimensions) {
|
while !self.sub.usable.fits(new_dimensions) {
|
||||||
if self.space_is_last() && self.space_is_empty() {
|
if self.space_is_last() && self.space_is_empty() {
|
||||||
println!("usable: {}", self.sub.usable);
|
|
||||||
println!("dims: {}", new_dimensions);
|
|
||||||
println!("size: {}", size);
|
|
||||||
Err(LayoutError::NotEnoughSpace("failed to add box to stack"))?;
|
Err(LayoutError::NotEnoughSpace("failed to add box to stack"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,14 +103,9 @@ impl StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let offset = self.sub.dimensions.y;
|
let offset = self.sub.dimensions.y;
|
||||||
let anchor = self.ctx.axes.anchor(size);
|
let anchor = self.ctx.axes.primary.anchor(size.x);
|
||||||
|
|
||||||
let pos = self.sub.origin + self.ctx.axes.specialize(
|
self.sub.boxes.push((offset, anchor, layout));
|
||||||
(self.sub.anchor - anchor)
|
|
||||||
+ Size2D::with_y(self.space.combined_dimensions.y + self.sub.factor * offset)
|
|
||||||
);
|
|
||||||
|
|
||||||
self.space.actions.add_layout(pos, layout);
|
|
||||||
self.sub.dimensions = new_dimensions;
|
self.sub.dimensions = new_dimensions;
|
||||||
self.sub.space = SpaceState::Allowed;
|
self.sub.space = SpaceState::Allowed;
|
||||||
|
|
||||||
@ -122,8 +119,8 @@ impl StackLayouter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_space(&mut self, space: Size, soft: bool) {
|
pub fn add_space(&mut self, space: Size, kind: SpaceKind) {
|
||||||
if soft {
|
if kind == SpaceKind::Soft {
|
||||||
if self.sub.space != SpaceState::Forbidden {
|
if self.sub.space != SpaceState::Forbidden {
|
||||||
self.sub.space = SpaceState::Soft(space);
|
self.sub.space = SpaceState::Soft(space);
|
||||||
}
|
}
|
||||||
@ -134,7 +131,9 @@ impl StackLayouter {
|
|||||||
self.sub.dimensions.y += space;
|
self.sub.dimensions.y += space;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.sub.space = SpaceState::Forbidden;
|
if kind == SpaceKind::Hard {
|
||||||
|
self.sub.space = SpaceState::Forbidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,6 +219,20 @@ impl StackLayouter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn finish_subspace(&mut self) {
|
fn finish_subspace(&mut self) {
|
||||||
|
let factor = self.ctx.axes.secondary.axis.factor();
|
||||||
|
let anchor =
|
||||||
|
self.ctx.axes.anchor(self.sub.usable)
|
||||||
|
- self.ctx.axes.anchor(Size2D::with_y(self.sub.dimensions.y));
|
||||||
|
|
||||||
|
for (offset, layout_anchor, layout) in self.sub.boxes.drain(..) {
|
||||||
|
let pos = self.sub.origin
|
||||||
|
+ self.ctx.axes.specialize(
|
||||||
|
anchor + Size2D::new(-layout_anchor, factor * offset)
|
||||||
|
);
|
||||||
|
|
||||||
|
self.space.actions.add_layout(pos, layout);
|
||||||
|
}
|
||||||
|
|
||||||
if self.ctx.axes.primary.needs_expansion() {
|
if self.ctx.axes.primary.needs_expansion() {
|
||||||
self.sub.dimensions.x = self.sub.usable.x;
|
self.sub.dimensions.x = self.sub.usable.x;
|
||||||
}
|
}
|
||||||
|
@ -58,16 +58,19 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn layout_space(&mut self) {
|
fn layout_space(&mut self) {
|
||||||
self.flex.add_primary_space(word_spacing(&self.style), true);
|
self.flex.add_primary_space(word_spacing(&self.style), SpaceKind::Soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_paragraph(&mut self) -> LayoutResult<()> {
|
fn layout_paragraph(&mut self) -> LayoutResult<()> {
|
||||||
self.flex.add_secondary_space(paragraph_spacing(&self.style), true)
|
self.flex.add_secondary_space(paragraph_spacing(&self.style), SpaceKind::Soft)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> {
|
fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> {
|
||||||
let (first, second) = self.flex.remaining()?;
|
let (first, second) = self.flex.remaining()?;
|
||||||
|
|
||||||
|
let mut axes = self.ctx.axes.expanding(false);
|
||||||
|
axes.secondary.alignment = Alignment::Origin;
|
||||||
|
|
||||||
let ctx = |spaces| {
|
let ctx = |spaces| {
|
||||||
LayoutContext {
|
LayoutContext {
|
||||||
loader: self.ctx.loader,
|
loader: self.ctx.loader,
|
||||||
@ -75,7 +78,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
text_style: &self.style,
|
text_style: &self.style,
|
||||||
page_style: self.ctx.page_style,
|
page_style: self.ctx.page_style,
|
||||||
spaces,
|
spaces,
|
||||||
axes: self.ctx.axes.expanding(false),
|
axes,
|
||||||
expand: false,
|
expand: false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -106,8 +109,10 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
Command::Add(layout) => self.flex.add(layout),
|
Command::Add(layout) => self.flex.add(layout),
|
||||||
Command::AddMultiple(layouts) => self.flex.add_multiple(layouts),
|
Command::AddMultiple(layouts) => self.flex.add_multiple(layouts),
|
||||||
|
|
||||||
Command::AddPrimarySpace(space) => self.flex.add_primary_space(space, false),
|
Command::AddPrimarySpace(space)
|
||||||
Command::AddSecondarySpace(space) => self.flex.add_secondary_space(space, false)?,
|
=> self.flex.add_primary_space(space, SpaceKind::Hard),
|
||||||
|
Command::AddSecondarySpace(space)
|
||||||
|
=> self.flex.add_secondary_space(space, SpaceKind::Hard)?,
|
||||||
|
|
||||||
Command::FinishLine => self.flex.add_break(),
|
Command::FinishLine => self.flex.add_break(),
|
||||||
Command::FinishRun => { self.flex.finish_run()?; },
|
Command::FinishRun => { self.flex.finish_run()?; },
|
||||||
|
@ -4,6 +4,8 @@ use crate::func::prelude::*;
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Align {
|
pub struct Align {
|
||||||
body: Option<SyntaxTree>,
|
body: Option<SyntaxTree>,
|
||||||
|
positional_1: Option<AlignSpecifier>,
|
||||||
|
positional_2: Option<AlignSpecifier>,
|
||||||
primary: Option<AlignSpecifier>,
|
primary: Option<AlignSpecifier>,
|
||||||
secondary: Option<AlignSpecifier>,
|
secondary: Option<AlignSpecifier>,
|
||||||
horizontal: Option<AlignSpecifier>,
|
horizontal: Option<AlignSpecifier>,
|
||||||
@ -29,6 +31,8 @@ function! {
|
|||||||
|
|
||||||
let mut align = Align {
|
let mut align = Align {
|
||||||
body,
|
body,
|
||||||
|
positional_1: None,
|
||||||
|
positional_2: None,
|
||||||
primary: None,
|
primary: None,
|
||||||
secondary: None,
|
secondary: None,
|
||||||
horizontal: None,
|
horizontal: None,
|
||||||
@ -36,7 +40,11 @@ function! {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(arg) = args.get_pos_opt::<ArgIdent>()? {
|
if let Some(arg) = args.get_pos_opt::<ArgIdent>()? {
|
||||||
align.primary = Some(parse_align_specifier(arg)?);
|
align.positional_1 = Some(parse_align_specifier(arg)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(arg) = args.get_pos_opt::<ArgIdent>()? {
|
||||||
|
align.positional_2 = Some(parse_align_specifier(arg)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parse_arg = |axis, target: &mut Option<AlignSpecifier>| {
|
let mut parse_arg = |axis, target: &mut Option<AlignSpecifier>| {
|
||||||
@ -92,6 +100,16 @@ function! {
|
|||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(spec) = this.positional_1 {
|
||||||
|
let positional = generic_alignment(spec, primary_horizontal).is_ok();
|
||||||
|
set_axis(positional, this.positional_1)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(spec) = this.positional_2 {
|
||||||
|
let positional = generic_alignment(spec, primary_horizontal).is_ok();
|
||||||
|
set_axis(positional, this.positional_2)?;
|
||||||
|
}
|
||||||
|
|
||||||
set_axis(true, this.primary)?;
|
set_axis(true, this.primary)?;
|
||||||
set_axis(false, this.secondary)?;
|
set_axis(false, this.secondary)?;
|
||||||
set_axis(primary_horizontal, this.horizontal)?;
|
set_axis(primary_horizontal, this.horizontal)?;
|
||||||
|
@ -4,18 +4,34 @@ use crate::func::prelude::*;
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Boxed {
|
pub struct Boxed {
|
||||||
body: SyntaxTree,
|
body: SyntaxTree,
|
||||||
|
width: Option<Size>,
|
||||||
|
height: Option<Size>,
|
||||||
}
|
}
|
||||||
|
|
||||||
function! {
|
function! {
|
||||||
data: Boxed,
|
data: Boxed,
|
||||||
|
|
||||||
parse(args, body, ctx) {
|
parse(args, body, ctx) {
|
||||||
|
let width = args.get_key_opt::<ArgSize>("width")?.map(|a| a.val);
|
||||||
|
let height = args.get_key_opt::<ArgSize>("height")?.map(|a| a.val);
|
||||||
args.done()?;
|
args.done()?;
|
||||||
|
|
||||||
let body = parse!(required: body, ctx);
|
let body = parse!(required: body, ctx);
|
||||||
Ok(Boxed { body })
|
Ok(Boxed {
|
||||||
|
body,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
layout(this, ctx) {
|
layout(this, mut ctx) {
|
||||||
|
if let Some(width) = this.width {
|
||||||
|
ctx.spaces[0].dimensions.x = width;
|
||||||
|
}
|
||||||
|
if let Some(height) = this.height {
|
||||||
|
ctx.spaces[0].dimensions.y = height;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(commands![AddMultiple(layout_tree(&this.body, ctx)?)])
|
Ok(commands![AddMultiple(layout_tree(&this.body, ctx)?)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user