mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Fix alignment bugs ✔
This commit is contained in:
parent
f6cb4d725e
commit
14259c7d09
@ -25,8 +25,7 @@ pub struct FlexLayouter {
|
|||||||
|
|
||||||
merged_actions: LayoutActionList,
|
merged_actions: LayoutActionList,
|
||||||
merged_dimensions: Size2D,
|
merged_dimensions: Size2D,
|
||||||
max_left: Size,
|
max_extent: Size,
|
||||||
max_right: Size,
|
|
||||||
|
|
||||||
usable: Size,
|
usable: Size,
|
||||||
run: FlexRun,
|
run: FlexRun,
|
||||||
@ -59,7 +58,7 @@ enum FlexUnit {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct FlexRun {
|
struct FlexRun {
|
||||||
content: Vec<(Size, Size, Layout)>,
|
content: Vec<(Size, Layout)>,
|
||||||
size: Size2D,
|
size: Size2D,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +79,7 @@ impl FlexLayouter {
|
|||||||
|
|
||||||
merged_actions: LayoutActionList::new(),
|
merged_actions: LayoutActionList::new(),
|
||||||
merged_dimensions: Size2D::with_x(usable),
|
merged_dimensions: Size2D::with_x(usable),
|
||||||
max_left: Size::zero(),
|
max_extent: Size::zero(),
|
||||||
max_right: usable,
|
|
||||||
|
|
||||||
usable,
|
usable,
|
||||||
run: FlexRun { content: vec![], size: Size2D::zero() },
|
run: FlexRun { content: vec![], size: Size2D::zero() },
|
||||||
@ -179,6 +177,7 @@ impl FlexLayouter {
|
|||||||
|
|
||||||
if new_run_size > self.usable {
|
if new_run_size > self.usable {
|
||||||
self.space = None;
|
self.space = None;
|
||||||
|
self.finish_run()?;
|
||||||
|
|
||||||
while size.x > self.usable {
|
while size.x > self.usable {
|
||||||
if self.stack.in_last_space() {
|
if self.stack.in_last_space() {
|
||||||
@ -188,15 +187,12 @@ impl FlexLayouter {
|
|||||||
self.stack.finish_layout(true);
|
self.stack.finish_layout(true);
|
||||||
self.usable = self.stack.usable().x;
|
self.usable = self.stack.usable().x;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finish_run()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layout_space();
|
self.layout_space();
|
||||||
|
|
||||||
let offset = self.run.size.x;
|
let offset = self.run.size.x;
|
||||||
let anchor = self.ctx.axes.primary.anchor(size.x);
|
self.run.content.push((offset, boxed));
|
||||||
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);
|
||||||
@ -215,22 +211,35 @@ impl FlexLayouter {
|
|||||||
fn layout_set_axes(&mut self, axes: LayoutAxes) {
|
fn layout_set_axes(&mut self, axes: LayoutAxes) {
|
||||||
if axes.primary != self.ctx.axes.primary {
|
if axes.primary != self.ctx.axes.primary {
|
||||||
self.finish_aligned_run();
|
self.finish_aligned_run();
|
||||||
|
|
||||||
self.usable = match axes.primary.alignment {
|
self.usable = match axes.primary.alignment {
|
||||||
Alignment::Origin => self.max_right,
|
Alignment::Origin =>
|
||||||
Alignment::Center => self.max_right - self.max_left,
|
if self.max_extent == Size::zero() { self.usable } else { Size::zero() },
|
||||||
Alignment::End => self.merged_dimensions.x - self.max_left,
|
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 {
|
if axes.secondary != self.ctx.axes.secondary {
|
||||||
self.stack.set_axes(axes);
|
self.stack.set_axes(axes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.ctx.axes = axes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the current flex run.
|
/// Finish the current flex run.
|
||||||
fn finish_run(&mut self) -> LayoutResult<()> {
|
fn finish_run(&mut self) -> LayoutResult<()> {
|
||||||
self.finish_aligned_run();
|
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());
|
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),
|
||||||
@ -239,19 +248,25 @@ impl FlexLayouter {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.merged_dimensions.y = Size::zero();
|
self.merged_dimensions.y = Size::zero();
|
||||||
self.max_left = Size::zero();
|
self.max_extent = Size::zero();
|
||||||
self.max_right = self.merged_dimensions.x;
|
|
||||||
self.usable = self.merged_dimensions.x;
|
self.usable = self.merged_dimensions.x;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_aligned_run(&mut self) {
|
fn finish_aligned_run(&mut self) {
|
||||||
let anchor = self.ctx.axes.primary.anchor(self.merged_dimensions.x);
|
if self.run.content.is_empty() {
|
||||||
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (offset, layout_anchor, layout) in self.run.content.drain(..) {
|
let factor = if self.ctx.axes.primary.axis.is_positive() { 1 } else { -1 };
|
||||||
let general_position = Size2D::with_x(anchor - layout_anchor + factor * offset);
|
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);
|
let position = self.ctx.axes.specialize(general_position);
|
||||||
|
|
||||||
self.merged_actions.add_layout(position, layout);
|
self.merged_actions.add_layout(position, layout);
|
||||||
@ -274,6 +289,10 @@ impl FlexLayouter {
|
|||||||
|
|
||||||
/// Whether this layouter contains any items.
|
/// Whether this layouter contains any items.
|
||||||
pub fn box_is_empty(&self) -> bool {
|
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 {
|
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.
|
/// Serialize this layout into an output buffer.
|
||||||
pub fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
|
pub fn serialize<W: Write>(&self, f: &mut W) -> io::Result<()> {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -58,7 +58,7 @@ impl StackLayouter {
|
|||||||
|
|
||||||
// Search for a suitable space to insert the box.
|
// Search for a suitable space to insert the box.
|
||||||
while !self.usable.fits(new_dimensions) {
|
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"))?;
|
Err(LayoutError::NotEnoughSpace("cannot fit box into stack"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ impl StackLayouter {
|
|||||||
let anchor = self.ctx.axes.anchor(size);
|
let anchor = self.ctx.axes.anchor(size);
|
||||||
self.boxes.push((offset, anchor, layout));
|
self.boxes.push((offset, anchor, layout));
|
||||||
|
|
||||||
self.dimensions.y += size.y;
|
self.dimensions = new_dimensions;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -216,8 +216,8 @@ fn merge_sizes(a: Size2D, b: Size2D) -> Size2D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn needs_expansion(axis: AlignedAxis) -> bool {
|
fn needs_expansion(axis: AlignedAxis) -> bool {
|
||||||
match (axis.axis.is_positive(), axis.alignment) {
|
!matches!(
|
||||||
(true, Alignment::Origin) | (false, Alignment::End) => false,
|
(axis.axis.is_positive(), axis.alignment),
|
||||||
_ => true,
|
(true, Alignment::Origin) | (false, Alignment::End)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node::Space => {
|
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;
|
let space = self.style.word_spacing * self.style.font_size;
|
||||||
self.flex.add_primary_space(space);
|
self.flex.add_primary_space(space);
|
||||||
}
|
}
|
||||||
@ -68,6 +68,7 @@ impl<'a, 'p> TreeLayouter<'a, 'p> {
|
|||||||
let commands = func.body.val.layout(LayoutContext {
|
let commands = func.body.val.layout(LayoutContext {
|
||||||
style: &self.style,
|
style: &self.style,
|
||||||
spaces: self.flex.remaining()?,
|
spaces: self.flex.remaining()?,
|
||||||
|
shrink_to_fit: true,
|
||||||
.. self.ctx
|
.. 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.
|
/// Create a `Debug` implementation from a `Display` implementation.
|
||||||
macro_rules! debug_display {
|
macro_rules! debug_display {
|
||||||
($type:ident) => (
|
($type:ident) => (
|
||||||
@ -58,6 +68,7 @@ macro_rules! debug_display {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declare a module and reexport all its contents.
|
||||||
macro_rules! pub_use_mod {
|
macro_rules! pub_use_mod {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
mod $name;
|
mod $name;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user