summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-11-17 20:57:50 +0100
committerLaurenz <laurmaedje@gmail.com>2019-11-17 20:57:50 +0100
commit14259c7d09c12327b18aba21cc577e68ad283eda (patch)
tree0f9a7a138141e84cfcb8691f41e29f7493879eab
parentf6cb4d725ee6e4fd09b92b5af7348d11ac951b10 (diff)
Fix alignment bugs ✔
-rw-r--r--src/layout/flex.rs55
-rw-r--r--src/layout/mod.rs9
-rw-r--r--src/layout/stacked.rs12
-rw-r--r--src/layout/tree.rs3
-rw-r--r--src/macros.rs11
5 files changed, 56 insertions, 34 deletions
diff --git a/src/layout/flex.rs b/src/layout/flex.rs
index bae700ce..8142461f 100644
--- a/src/layout/flex.rs
+++ b/src/layout/flex.rs
@@ -25,8 +25,7 @@ pub struct FlexLayouter {
merged_actions: LayoutActionList,
merged_dimensions: Size2D,
- max_left: Size,
- max_right: Size,
+ max_extent: Size,
usable: Size,
run: FlexRun,
@@ -59,7 +58,7 @@ enum FlexUnit {
#[derive(Debug, Clone)]
struct FlexRun {
- content: Vec<(Size, Size, Layout)>,
+ content: Vec<(Size, Layout)>,
size: Size2D,
}
@@ -80,8 +79,7 @@ impl FlexLayouter {
merged_actions: LayoutActionList::new(),
merged_dimensions: Size2D::with_x(usable),
- max_left: Size::zero(),
- max_right: usable,
+ max_extent: Size::zero(),
usable,
run: FlexRun { content: vec![], size: Size2D::zero() },
@@ -179,6 +177,7 @@ impl FlexLayouter {
if new_run_size > self.usable {
self.space = None;
+ self.finish_run()?;
while size.x > self.usable {
if self.stack.in_last_space() {
@@ -188,15 +187,12 @@ impl FlexLayouter {
self.stack.finish_layout(true);
self.usable = self.stack.usable().x;
}
-
- self.finish_run()?;
}
self.layout_space();
let offset = self.run.size.x;
- let anchor = self.ctx.axes.primary.anchor(size.x);
- self.run.content.push((offset, anchor, boxed));
+ self.run.content.push((offset, boxed));
self.run.size.x += size.x;
self.run.size.y = crate::size::max(self.run.size.y, size.y);
@@ -215,22 +211,35 @@ impl FlexLayouter {
fn layout_set_axes(&mut self, axes: LayoutAxes) {
if axes.primary != self.ctx.axes.primary {
self.finish_aligned_run();
+
self.usable = match axes.primary.alignment {
- Alignment::Origin => self.max_right,
- Alignment::Center => self.max_right - self.max_left,
- Alignment::End => self.merged_dimensions.x - self.max_left,
+ Alignment::Origin =>
+ if self.max_extent == Size::zero() { self.usable } else { Size::zero() },
+ Alignment::Center => crate::size::max(
+ self.merged_dimensions.x - 2 * self.max_extent,
+ Size::zero()
+ ),
+ Alignment::End => self.merged_dimensions.x - self.max_extent,
};
}
if axes.secondary != self.ctx.axes.secondary {
self.stack.set_axes(axes);
}
+
+ self.ctx.axes = axes;
}
/// Finish the current flex run.
fn finish_run(&mut self) -> LayoutResult<()> {
self.finish_aligned_run();
+ if self.merged_dimensions.y == Size::zero() {
+ 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),
@@ -239,19 +248,25 @@ impl FlexLayouter {
})?;
self.merged_dimensions.y = Size::zero();
- self.max_left = Size::zero();
- self.max_right = self.merged_dimensions.x;
+ self.max_extent = Size::zero();
self.usable = self.merged_dimensions.x;
Ok(())
}
fn finish_aligned_run(&mut self) {
- let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x);
+ if self.run.content.is_empty() {
+ return;
+ }
+
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
+ let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x)
+ - self.ctx.axes.primary.anchor(self.run.size.x);
- for (offset, layout_anchor, layout) in self.run.content.drain(..) {
- let general_position = Size2D::with_x(anchor - layout_anchor + factor * offset);
+ self.max_extent = crate::size::max(self.max_extent, anchor + factor * self.run.size.x);
+
+ for (offset, layout) in self.run.content.drain(..) {
+ let general_position = Size2D::with_x(anchor + factor * offset);
let position = self.ctx.axes.specialize(general_position);
self.merged_actions.add_layout(position, layout);
@@ -274,6 +289,10 @@ impl FlexLayouter {
/// Whether this layouter contains any items.
pub fn box_is_empty(&self) -> bool {
- self.units.is_empty()
+ !self.units.iter().any(|unit| matches!(unit, FlexUnit::Boxed(_)))
+ }
+
+ pub fn last_is_space(&self) -> bool {
+ matches!(self.units.last(), Some(FlexUnit::Space(_)))
}
}
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index fb63ff86..a4514704 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -41,15 +41,6 @@ pub struct Layout {
}
impl Layout {
- /// Create an empty layout with the specified dimensions.
- pub fn empty(width: Size, height: Size) -> Layout {
- Layout {
- dimensions: Size2D::new(width, height),
- actions: vec![],
- debug_render: true,
- }
- }
-
/// Serialize this layout into an output buffer.
pub fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
writeln!(
diff --git a/src/layout/stacked.rs b/src/layout/stacked.rs
index 8113a4b7..b77c0582 100644
--- a/src/layout/stacked.rs
+++ b/src/layout/stacked.rs
@@ -58,7 +58,7 @@ impl StackLayouter {
// Search for a suitable space to insert the box.
while !self.usable.fits(new_dimensions) {
- if self.in_last_space() {
+ if self.boxes.is_empty() && self.in_last_space() {
Err(LayoutError::NotEnoughSpace("cannot fit box into stack"))?;
}
@@ -70,7 +70,7 @@ impl StackLayouter {
let anchor = self.ctx.axes.anchor(size);
self.boxes.push((offset, anchor, layout));
- self.dimensions.y += size.y;
+ self.dimensions = new_dimensions;
Ok(())
}
@@ -216,8 +216,8 @@ fn merge_sizes(a: Size2D, b: Size2D) -> Size2D {
}
fn needs_expansion(axis: AlignedAxis) -> bool {
- match (axis.axis.is_positive(), axis.alignment) {
- (true, Alignment::Origin) | (false, Alignment::End) => false,
- _ => true,
- }
+ !matches!(
+ (axis.axis.is_positive(), axis.alignment),
+ (true, Alignment::Origin) | (false, Alignment::End)
+ )
}
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 11e83209..b60ead9c 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -41,7 +41,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
}
Node::Space => {
- if !self.flex.box_is_empty() {
+ if !self.flex.box_is_empty() && !self.flex.last_is_space() {
let space = self.style.word_spacing * self.style.font_size;
self.flex.add_primary_space(space);
}
@@ -68,6 +68,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
let commands = func.body.val.layout(LayoutContext {
style: &self.style,
spaces: self.flex.remaining()?,
+ shrink_to_fit: true,
.. self.ctx
})?;
diff --git a/src/macros.rs b/src/macros.rs
index e7113672..b6f069b7 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -40,6 +40,16 @@ macro_rules! error_type {
};
}
+/// Shorthand for checking whether an expression matches a pattern.
+macro_rules! matches {
+ ($expr:expr, $($pattern:tt)*) => {
+ match $expr {
+ $($pattern)* => true,
+ _ => false,
+ }
+ };
+}
+
/// Create a `Debug` implementation from a `Display` implementation.
macro_rules! debug_display {
($type:ident) => (
@@ -58,6 +68,7 @@ macro_rules! debug_display {
);
}
+/// Declare a module and reexport all its contents.
macro_rules! pub_use_mod {
($name:ident) => {
mod $name;