Axes updating for flex layouter 📐

This commit is contained in:
Laurenz 2019-11-17 14:51:31 +01:00
parent 1f009b5b95
commit 4d0bdc4ca4
3 changed files with 71 additions and 31 deletions

View File

@ -23,6 +23,11 @@ pub struct FlexLayouter {
stack: StackLayouter, stack: StackLayouter,
units: Vec<FlexUnit>, units: Vec<FlexUnit>,
merged_actions: LayoutActionList,
merged_dimensions: Size2D,
max_left: Size,
max_right: Size,
usable: Size, usable: Size,
run: FlexRun, run: FlexRun,
space: Option<Size>, space: Option<Size>,
@ -54,7 +59,7 @@ enum FlexUnit {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct FlexRun { struct FlexRun {
content: Vec<(Size, Layout)>, content: Vec<(Size, Size, Layout)>,
size: Size2D, size: Size2D,
} }
@ -67,12 +72,18 @@ impl FlexLayouter {
shrink_to_fit: ctx.shrink_to_fit, shrink_to_fit: ctx.shrink_to_fit,
}); });
let usable = stack.usable().x;
FlexLayouter { FlexLayouter {
ctx, ctx,
units: vec![], units: vec![],
stack, stack,
usable: stack.usable().x, merged_actions: LayoutActionList::new(),
merged_dimensions: Size2D::with_x(usable),
max_left: Size::zero(),
max_right: usable,
usable,
run: FlexRun { content: vec![], size: Size2D::zero() }, run: FlexRun { content: vec![], size: Size2D::zero() },
space: None, space: None,
} }
@ -158,27 +169,6 @@ impl FlexLayouter {
Ok(()) Ok(())
} }
/// Finish the current flex run.
fn finish_run(&mut self) -> LayoutResult<()> {
let mut actions = LayoutActionList::new();
for (x, layout) in self.run.content.drain(..) {
let position = self.ctx.axes.specialize(Size2D::with_x(x));
actions.add_layout(position, layout);
}
self.run.size.y += self.ctx.flex_spacing;
self.stack.add(Layout {
dimensions: self.ctx.axes.specialize(self.run.size),
actions: actions.into_vec(),
debug_render: false,
})?;
self.run.size = Size2D::zero();
Ok(())
}
/// Layout a content box into the current flex run or start a new run if /// Layout a content box into the current flex run or start a new run if
/// it does not fit. /// it does not fit.
fn layout_box(&mut self, boxed: Layout) -> LayoutResult<()> { fn layout_box(&mut self, boxed: Layout) -> LayoutResult<()> {
@ -204,7 +194,10 @@ impl FlexLayouter {
self.layout_space(); self.layout_space();
self.run.content.push((self.run.size.x, boxed)); let offset = self.run.size.x;
let anchor = self.ctx.axes.primary.anchor(size.x);
self.run.content.push((offset, anchor, boxed));
self.run.size.x += size.x; self.run.size.x += size.x;
self.run.size.y = crate::size::max(self.run.size.y, size.y); self.run.size.y = crate::size::max(self.run.size.y, size.y);
@ -220,7 +213,54 @@ impl FlexLayouter {
} }
fn layout_set_axes(&mut self, axes: LayoutAxes) { fn layout_set_axes(&mut self, axes: LayoutAxes) {
// TODO 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,
};
}
if axes.secondary != self.ctx.axes.secondary {
self.stack.set_axes(axes);
}
}
/// Finish the current flex run.
fn finish_run(&mut self) -> LayoutResult<()> {
self.finish_aligned_run();
let actions = std::mem::replace(&mut self.merged_actions, LayoutActionList::new());
self.stack.add(Layout {
dimensions: self.ctx.axes.specialize(self.merged_dimensions),
actions: actions.into_vec(),
debug_render: false,
})?;
self.merged_dimensions.y = Size::zero();
self.max_left = Size::zero();
self.max_right = self.merged_dimensions.x;
self.usable = self.merged_dimensions.x;
Ok(())
}
fn finish_aligned_run(&mut self) -> LayoutResult<()> {
let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x);
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
for (offset, layout_anchor, layout) in self.run.content.drain(..) {
let general_position = Size2D::with_x(anchor - layout_anchor + factor * offset);
let position = self.ctx.axes.specialize(general_position);
self.merged_actions.add_layout(position, layout);
}
self.merged_dimensions.y = crate::size::max(self.merged_dimensions.y, self.run.size.y);
self.run.size = Size2D::zero();
Ok(())
} }
/// This layouter's context. /// This layouter's context.

View File

@ -202,20 +202,20 @@ impl LayoutAxes {
/// the layouting axes, that is: /// the layouting axes, that is:
/// - The x coordinate describes the primary axis instead of the horizontal one. /// - The x coordinate describes the primary axis instead of the horizontal one.
/// - The y coordinate describes the secondary axis instead of the vertical one. /// - The y coordinate describes the secondary axis instead of the vertical one.
pub fn generalize(&self, space: Size2D) -> Size2D { pub fn generalize(&self, size: Size2D) -> Size2D {
if self.primary.axis.is_horizontal() { if self.primary.axis.is_horizontal() {
space size
} else { } else {
Size2D { x: space.y, y: space.x } Size2D { x: size.y, y: size.x }
} }
} }
/// Returns the specialized version of this generalized Size2D. /// Returns the specialized version of this generalized Size2D.
/// (Inverse to `generalized`). /// (Inverse to `generalized`).
pub fn specialize(&self, space: Size2D) -> Size2D { pub fn specialize(&self, size: Size2D) -> Size2D {
// In fact, generalized is its own inverse. For reasons of clarity // In fact, generalized is its own inverse. For reasons of clarity
// at the call site, we still have this second function. // at the call site, we still have this second function.
self.generalize(space) self.generalize(size)
} }
/// The position of the anchor specified by the two aligned axes /// The position of the anchor specified by the two aligned axes

View File

@ -150,7 +150,7 @@ impl StackLayouter {
let factor = if self.ctx.axes.secondary.axis.is_positive() { 1 } else { -1 }; let factor = if self.ctx.axes.secondary.axis.is_positive() { 1 } else { -1 };
for (offset, layout_anchor, layout) in self.boxes.drain(..) { for (offset, layout_anchor, layout) in self.boxes.drain(..) {
let general_position = anchor - layout_anchor + Size2D::with_y(offset * factor); let general_position = anchor - layout_anchor + Size2D::with_y(factor * offset);
let position = start + self.ctx.axes.specialize(general_position); let position = start + self.ctx.axes.specialize(general_position);
self.merged_actions.add_layout(position, layout); self.merged_actions.add_layout(position, layout);