From 1eb25f86dd6763c4f2d7e60b6d09af60ada50af6 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 18 Nov 2019 12:57:14 +0100 Subject: [PATCH] =?UTF-8?q?Double-try=20spaces=20for=20functions=20?= =?UTF-8?q?=F0=9F=8C=91=F0=9F=8C=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/flex.rs | 62 +++++++++++++++++++++++++---------- src/layout/stacked.rs | 2 +- src/layout/tree.rs | 18 ++++++++-- src/library/axes.rs | 17 +++++----- src/library/style.rs | 8 ++--- tests/layouts/align.typ | 3 +- tests/layouts/coma.typ | 10 +++--- tests/layouts/shakespeare.typ | 4 +-- 8 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/layout/flex.rs b/src/layout/flex.rs index 8142461f5..0ad31521c 100644 --- a/src/layout/flex.rs +++ b/src/layout/flex.rs @@ -23,6 +23,7 @@ pub struct FlexLayouter { stack: StackLayouter, units: Vec, + total_usable: Size, merged_actions: LayoutActionList, merged_dimensions: Size2D, max_extent: Size, @@ -30,6 +31,8 @@ pub struct FlexLayouter { usable: Size, run: FlexRun, space: Option, + + last_run_remaining: Size2D, } /// The context for flex layouting. @@ -77,13 +80,16 @@ impl FlexLayouter { units: vec![], stack, + total_usable: usable, merged_actions: LayoutActionList::new(), - merged_dimensions: Size2D::with_x(usable), + merged_dimensions: Size2D::zero(), max_extent: Size::zero(), usable, run: FlexRun { content: vec![], size: Size2D::zero() }, space: None, + + last_run_remaining: Size2D::zero(), } } @@ -172,10 +178,7 @@ impl FlexLayouter { fn layout_box(&mut self, boxed: Layout) -> LayoutResult<()> { let size = self.ctx.axes.generalize(boxed.dimensions); - let space = self.space.unwrap_or(Size::zero()); - let new_run_size = self.run.size.x + space + size.x; - - if new_run_size > self.usable { + if size.x > self.size_left() { self.space = None; self.finish_run()?; @@ -185,7 +188,8 @@ impl FlexLayouter { } 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 { 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( - self.merged_dimensions.x - 2 * self.max_extent, + self.total_usable - 2 * self.max_extent, 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(()); } - self.merged_dimensions.y += self.ctx.flex_spacing; - let actions = std::mem::replace(&mut self.merged_actions, LayoutActionList::new()); self.stack.add(Layout { dimensions: self.ctx.axes.specialize(self.merged_dimensions), @@ -247,9 +253,9 @@ impl FlexLayouter { debug_render: false, })?; - self.merged_dimensions.y = Size::zero(); + self.merged_dimensions = Size2D::zero(); self.max_extent = Size::zero(); - self.usable = self.merged_dimensions.x; + self.usable = self.total_usable; Ok(()) } @@ -260,7 +266,7 @@ impl FlexLayouter { } 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.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_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(); } @@ -281,10 +297,17 @@ impl FlexLayouter { &self.ctx } - pub fn remaining(&self) -> LayoutResult { + pub fn remaining(&self) -> LayoutResult<(LayoutSpaces, LayoutSpaces)> { let mut future = self.clone(); 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. @@ -295,4 +318,9 @@ impl FlexLayouter { pub fn last_is_space(&self) -> bool { 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) + } } diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs index b77c0582f..a75850460 100644 --- a/src/layout/stacked.rs +++ b/src/layout/stacked.rs @@ -41,7 +41,7 @@ impl StackLayouter { layouts: MultiLayout::new(), merged_actions: LayoutActionList::new(), - merged_dimensions: space.start(), + merged_dimensions: Size2D::zero(), boxes: vec![], usable, diff --git a/src/layout/tree.rs b/src/layout/tree.rs index b60ead9cb..177a6308a 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -65,12 +65,24 @@ impl<'a, 'p> TreeLayouter<'a, 'p> { /// Layout a function. 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, - spaces: self.flex.remaining()?, + spaces: spaces, shrink_to_fit: true, .. 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 { self.execute(command)?; diff --git a/src/library/axes.rs b/src/library/axes.rs index 62e0078f2..1f3525f67 100644 --- a/src/library/axes.rs +++ b/src/library/axes.rs @@ -28,16 +28,17 @@ function! { } layout(this, ctx) { - let mut new_axes = ctx.axes; - new_axes.primary.alignment = this.alignment; + let mut axes = ctx.axes; + axes.primary.alignment = this.alignment; Ok(match &this.body { - Some(body) => commands![ - SetAxes(new_axes), - LayoutTree(body), - SetAxes(ctx.axes), - ], - None => commands![Command::SetAxes(new_axes)] + Some(body) => commands![AddMultiple( + layout_tree(body, LayoutContext { + axes, + .. ctx.clone() + })? + )], + None => commands![Command::SetAxes(axes)] }) } } diff --git a/src/library/style.rs b/src/library/style.rs index 90a5fd31b..0615c0e7b 100644 --- a/src/library/style.rs +++ b/src/library/style.rs @@ -18,16 +18,16 @@ macro_rules! stylefunc { } layout(this, ctx) { - let mut new_style = ctx.style.clone(); - new_style.toggle_class(FontClass::$ident); + let mut style = ctx.style.clone(); + style.toggle_class(FontClass::$ident); Ok(match &this.body { Some(body) => commands![ - SetStyle(new_style), + SetStyle(style), LayoutTree(body), SetStyle(ctx.style.clone()), ], - None => commands![SetStyle(new_style)] + None => commands![SetStyle(style)] }) } } diff --git a/tests/layouts/align.typ b/tests/layouts/align.typ index 49365afc4..e993a43b3 100644 --- a/tests/layouts/align.typ +++ b/tests/layouts/align.typ @@ -29,5 +29,4 @@ Right Again: {lorem:10} [page.break] // ---------------------------------- // -// All in one line. -All in one line: {lorem:25} [align: right][{lorem:50}] {lorem:15} +All in one line: {lorem:25} [align: right] {lorem:50} [align: left] {lorem:15} diff --git a/tests/layouts/coma.typ b/tests/layouts/coma.typ index 4adabe0de..e9fb09947 100644 --- a/tests/layouts/coma.typ +++ b/tests/layouts/coma.typ @@ -1,14 +1,14 @@ {size:420pt x 300pt} -[box: flow = horizontal][ +[box][ *Technical University Berlin* [n] *Faculty II, Institute for Mathematics* [n] Secretary Example [n] Prof. Dr. Example [n] Assistant #1, Assistant #2, Assistant #3 - - [align: right][*WiSe 2019/2020* [n] Week 1] ] +[align: right][*WiSe 2019/2020* [n] Week 1] + [v: 3mm] [align: center][ @@ -17,9 +17,7 @@ *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. Die Tiefe eines Knotens _v_ ist die Länge des eindeutigen Weges von der Wurzel diff --git a/tests/layouts/shakespeare.typ b/tests/layouts/shakespeare.typ index 19450ce4e..8cffb9304 100644 --- a/tests/layouts/shakespeare.typ +++ b/tests/layouts/shakespeare.typ @@ -1,3 +1,3 @@ -[align: center][{include:shakespeare.tpl}] -[align: left][{include:shakespeare.tpl}] +[align: center][{include:shakespeare.tpl}] [page.break] +[align: left][{include:shakespeare.tpl}] [page.break] [align: right][{include:shakespeare.tpl}]