Fix alignment bugs ✔
This commit is contained in:
parent
f6cb4d725e
commit
14259c7d09
@ -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);
|
||||
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
|
||||
if self.run.content.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset, layout_anchor, layout) in self.run.content.drain(..) {
|
||||
let general_position = Size2D::with_x(anchor - layout_anchor + factor * offset);
|
||||
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);
|
||||
|
||||
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(_)))
|
||||
}
|
||||
}
|
||||
|
@ -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!(
|
||||
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
})?;
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user