Fix secondary non-origin alignment 🚧

This commit is contained in:
Laurenz 2019-11-22 20:15:00 +01:00
parent 4ab7ec6a9a
commit 6ff60bc368
6 changed files with 102 additions and 38 deletions

View File

@ -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;
}
} }
} }

View File

@ -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,

View File

@ -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;
} }

View File

@ -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()?; },

View File

@ -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)?;

View File

@ -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)?)])
} }
} }