Double-try spaces for functions 🌑🌕

This commit is contained in:
Laurenz 2019-11-18 12:57:14 +01:00
parent 14259c7d09
commit 1eb25f86dd
8 changed files with 81 additions and 43 deletions

View File

@ -23,6 +23,7 @@ pub struct FlexLayouter {
stack: StackLayouter, stack: StackLayouter,
units: Vec<FlexUnit>, units: Vec<FlexUnit>,
total_usable: Size,
merged_actions: LayoutActionList, merged_actions: LayoutActionList,
merged_dimensions: Size2D, merged_dimensions: Size2D,
max_extent: Size, max_extent: Size,
@ -30,6 +31,8 @@ pub struct FlexLayouter {
usable: Size, usable: Size,
run: FlexRun, run: FlexRun,
space: Option<Size>, space: Option<Size>,
last_run_remaining: Size2D,
} }
/// The context for flex layouting. /// The context for flex layouting.
@ -77,13 +80,16 @@ impl FlexLayouter {
units: vec![], units: vec![],
stack, stack,
total_usable: usable,
merged_actions: LayoutActionList::new(), merged_actions: LayoutActionList::new(),
merged_dimensions: Size2D::with_x(usable), merged_dimensions: Size2D::zero(),
max_extent: Size::zero(), max_extent: Size::zero(),
usable, usable,
run: FlexRun { content: vec![], size: Size2D::zero() }, run: FlexRun { content: vec![], size: Size2D::zero() },
space: None, space: None,
last_run_remaining: Size2D::zero(),
} }
} }
@ -172,10 +178,7 @@ impl FlexLayouter {
fn layout_box(&mut self, boxed: Layout) -> LayoutResult<()> { fn layout_box(&mut self, boxed: Layout) -> LayoutResult<()> {
let size = self.ctx.axes.generalize(boxed.dimensions); let size = self.ctx.axes.generalize(boxed.dimensions);
let space = self.space.unwrap_or(Size::zero()); if size.x > self.size_left() {
let new_run_size = self.run.size.x + space + size.x;
if new_run_size > self.usable {
self.space = None; self.space = None;
self.finish_run()?; self.finish_run()?;
@ -185,7 +188,8 @@ impl FlexLayouter {
} }
self.stack.finish_layout(true); self.stack.finish_layout(true);
self.usable = self.stack.usable().x; self.total_usable = self.stack.usable().x;
self.usable = self.total_usable;
} }
} }
@ -214,12 +218,16 @@ impl FlexLayouter {
self.usable = match axes.primary.alignment { self.usable = match axes.primary.alignment {
Alignment::Origin => Alignment::Origin =>
if self.max_extent == Size::zero() { self.usable } else { Size::zero() }, if self.max_extent == Size::zero() {
self.total_usable
} else {
Size::zero()
},
Alignment::Center => crate::size::max( Alignment::Center => crate::size::max(
self.merged_dimensions.x - 2 * self.max_extent, self.total_usable - 2 * self.max_extent,
Size::zero() Size::zero()
), ),
Alignment::End => self.merged_dimensions.x - self.max_extent, Alignment::End => self.total_usable - self.max_extent,
}; };
} }
@ -238,8 +246,6 @@ impl FlexLayouter {
return Ok(()); return Ok(());
} }
self.merged_dimensions.y += self.ctx.flex_spacing;
let actions = std::mem::replace(&mut self.merged_actions, LayoutActionList::new()); let actions = std::mem::replace(&mut self.merged_actions, LayoutActionList::new());
self.stack.add(Layout { self.stack.add(Layout {
dimensions: self.ctx.axes.specialize(self.merged_dimensions), dimensions: self.ctx.axes.specialize(self.merged_dimensions),
@ -247,9 +253,9 @@ impl FlexLayouter {
debug_render: false, debug_render: false,
})?; })?;
self.merged_dimensions.y = Size::zero(); self.merged_dimensions = Size2D::zero();
self.max_extent = Size::zero(); self.max_extent = Size::zero();
self.usable = self.merged_dimensions.x; self.usable = self.total_usable;
Ok(()) Ok(())
} }
@ -260,7 +266,7 @@ impl FlexLayouter {
} }
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 }; let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x) let anchor = self.ctx.axes.primary.anchor(self.total_usable)
- self.ctx.axes.primary.anchor(self.run.size.x); - self.ctx.axes.primary.anchor(self.run.size.x);
self.max_extent = crate::size::max(self.max_extent, anchor + factor * self.run.size.x); self.max_extent = crate::size::max(self.max_extent, anchor + factor * self.run.size.x);
@ -272,7 +278,17 @@ impl FlexLayouter {
self.merged_actions.add_layout(position, layout); self.merged_actions.add_layout(position, layout);
} }
self.merged_dimensions.y = crate::size::max(self.merged_dimensions.y, self.run.size.y); self.merged_dimensions.x = match self.ctx.axes.primary.alignment {
Alignment::Origin => self.run.size.x,
Alignment::Center | Alignment::End => self.total_usable,
};
self.merged_dimensions.y = crate::size::max(
self.merged_dimensions.y,
self.run.size.y + self.ctx.flex_spacing,
);
self.last_run_remaining = Size2D::new(self.size_left(), self.merged_dimensions.y);
self.run.size = Size2D::zero(); self.run.size = Size2D::zero();
} }
@ -281,10 +297,17 @@ impl FlexLayouter {
&self.ctx &self.ctx
} }
pub fn remaining(&self) -> LayoutResult<LayoutSpaces> { pub fn remaining(&self) -> LayoutResult<(LayoutSpaces, LayoutSpaces)> {
let mut future = self.clone(); let mut future = self.clone();
future.finish_box()?; future.finish_box()?;
Ok(future.stack.remaining())
let stack_spaces = future.stack.remaining();
let mut flex_spaces = stack_spaces.clone();
flex_spaces[0].dimensions.x = future.last_run_remaining.x;
flex_spaces[0].dimensions.y += future.last_run_remaining.y;
Ok((flex_spaces, stack_spaces))
} }
/// Whether this layouter contains any items. /// Whether this layouter contains any items.
@ -295,4 +318,9 @@ impl FlexLayouter {
pub fn last_is_space(&self) -> bool { pub fn last_is_space(&self) -> bool {
matches!(self.units.last(), Some(FlexUnit::Space(_))) matches!(self.units.last(), Some(FlexUnit::Space(_)))
} }
fn size_left(&self) -> Size {
let space = self.space.unwrap_or(Size::zero());
self.usable - (self.run.size.x + space)
}
} }

View File

@ -41,7 +41,7 @@ impl StackLayouter {
layouts: MultiLayout::new(), layouts: MultiLayout::new(),
merged_actions: LayoutActionList::new(), merged_actions: LayoutActionList::new(),
merged_dimensions: space.start(), merged_dimensions: Size2D::zero(),
boxes: vec![], boxes: vec![],
usable, usable,

View File

@ -65,12 +65,24 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
/// Layout a function. /// Layout a function.
fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> { fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> {
let commands = func.body.val.layout(LayoutContext { let (flex_spaces, stack_spaces) = self.flex.remaining()?;
let ctx = |spaces| LayoutContext {
style: &self.style, style: &self.style,
spaces: self.flex.remaining()?, spaces: spaces,
shrink_to_fit: true, shrink_to_fit: true,
.. self.ctx .. self.ctx
})?; };
// Try putting it in the flex space first, but if that is not enough
// space, use the other space.
let commands = match func.body.val.layout(ctx(flex_spaces)) {
Ok(c) => c,
Err(LayoutError::NotEnoughSpace(_)) => {
func.body.val.layout(ctx(stack_spaces))?
},
e => e?,
};
for command in commands { for command in commands {
self.execute(command)?; self.execute(command)?;

View File

@ -28,16 +28,17 @@ function! {
} }
layout(this, ctx) { layout(this, ctx) {
let mut new_axes = ctx.axes; let mut axes = ctx.axes;
new_axes.primary.alignment = this.alignment; axes.primary.alignment = this.alignment;
Ok(match &this.body { Ok(match &this.body {
Some(body) => commands![ Some(body) => commands![AddMultiple(
SetAxes(new_axes), layout_tree(body, LayoutContext {
LayoutTree(body), axes,
SetAxes(ctx.axes), .. ctx.clone()
], })?
None => commands![Command::SetAxes(new_axes)] )],
None => commands![Command::SetAxes(axes)]
}) })
} }
} }

View File

@ -18,16 +18,16 @@ macro_rules! stylefunc {
} }
layout(this, ctx) { layout(this, ctx) {
let mut new_style = ctx.style.clone(); let mut style = ctx.style.clone();
new_style.toggle_class(FontClass::$ident); style.toggle_class(FontClass::$ident);
Ok(match &this.body { Ok(match &this.body {
Some(body) => commands![ Some(body) => commands![
SetStyle(new_style), SetStyle(style),
LayoutTree(body), LayoutTree(body),
SetStyle(ctx.style.clone()), SetStyle(ctx.style.clone()),
], ],
None => commands![SetStyle(new_style)] None => commands![SetStyle(style)]
}) })
} }
} }

View File

@ -29,5 +29,4 @@ Right Again: {lorem:10}
[page.break] [page.break]
// ---------------------------------- // // ---------------------------------- //
// All in one line. All in one line: {lorem:25} [align: right] {lorem:50} [align: left] {lorem:15}
All in one line: {lorem:25} [align: right][{lorem:50}] {lorem:15}

View File

@ -1,14 +1,14 @@
{size:420pt x 300pt} {size:420pt x 300pt}
[box: flow = horizontal][ [box][
*Technical University Berlin* [n] *Technical University Berlin* [n]
*Faculty II, Institute for Mathematics* [n] *Faculty II, Institute for Mathematics* [n]
Secretary Example [n] Secretary Example [n]
Prof. Dr. Example [n] Prof. Dr. Example [n]
Assistant #1, Assistant #2, Assistant #3 Assistant #1, Assistant #2, Assistant #3
[align: right][*WiSe 2019/2020* [n] Week 1]
] ]
[align: right][*WiSe 2019/2020* [n] Week 1]
[v: 3mm] [v: 3mm]
[align: center][ [align: center][
@ -17,9 +17,7 @@
*Alle Antworten sind zu beweisen.* *Alle Antworten sind zu beweisen.*
] ]
[box: flow = horizontal][
*1. Aufgabe* [align: right][(1 + 1 + 2 Punkte)] *1. Aufgabe* [align: right][(1 + 1 + 2 Punkte)]
]
Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten 2 Kinder hat. Ein _Binärbaum_ ist ein Wurzelbaum, in dem jeder Knoten 2 Kinder hat.
Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel

View File

@ -1,3 +1,3 @@
[align: center][{include:shakespeare.tpl}] [align: center][{include:shakespeare.tpl}] [page.break]
[align: left][{include:shakespeare.tpl}] [align: left][{include:shakespeare.tpl}] [page.break]
[align: right][{include:shakespeare.tpl}] [align: right][{include:shakespeare.tpl}]