Some more layout features, align/stretch.
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::scene::{
|
||||
UiSize,
|
||||
};
|
||||
use crate::text::TextSystem;
|
||||
use crate::tree::{CursorIcon, Edges, Element, ElementId, FlexDirection, ImageNode, Style};
|
||||
use crate::tree::{AlignItems, CursorIcon, Edges, Element, ElementId, FlexDirection, ImageNode, Style};
|
||||
|
||||
pub fn layout_scene(version: u64, logical_size: UiSize, root: &Element) -> SceneSnapshot {
|
||||
let mut text_system = TextSystem::new();
|
||||
@@ -793,7 +793,11 @@ fn point_in_rounded_rect(point: crate::scene::Point, rect: Rect, radius: f32) ->
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct MeasuredChild {
|
||||
/// Offered cross-axis size (full available_cross for stretch; explicit value otherwise).
|
||||
cross: f32,
|
||||
/// Natural cross-axis size: set when parent uses non-stretch alignment, child has no
|
||||
/// explicit cross size, and the child is not flex. `None` means use `cross`.
|
||||
natural_cross: Option<f32>,
|
||||
main: f32,
|
||||
is_flex: bool,
|
||||
}
|
||||
@@ -870,6 +874,31 @@ fn layout_container_children(
|
||||
intrinsic.max(min_main_outer)
|
||||
}
|
||||
});
|
||||
// For non-stretch alignment, measure the child's natural cross size so it is not
|
||||
// forcibly stretched to fill the container's cross axis. Only done for non-flex
|
||||
// children with no explicit cross-axis style, since flex main size is unknown here.
|
||||
// align_self on the child overrides the parent's align_items for this child.
|
||||
let effective_align = child.style.align_self.unwrap_or(element.style.align_items);
|
||||
let natural_cross =
|
||||
if effective_align != AlignItems::Stretch
|
||||
&& !is_flex
|
||||
&& child_cross_size(child, element.style.direction).is_none()
|
||||
{
|
||||
let offered = match element.style.direction {
|
||||
FlexDirection::Row => UiSize::new(measured_main, available_cross),
|
||||
FlexDirection::Column => UiSize::new(available_cross, measured_main),
|
||||
};
|
||||
let natural =
|
||||
intrinsic_size(child, offered, text_system, perf_stats, layout_cache);
|
||||
Some(
|
||||
cross_axis_size(natural, element.style.direction)
|
||||
.max(min_cross_outer)
|
||||
.min(available_cross.max(min_cross_outer)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if is_flex {
|
||||
flex_total += child_flex_weight(child);
|
||||
} else {
|
||||
@@ -877,6 +906,7 @@ fn layout_container_children(
|
||||
}
|
||||
measured_children.push(MeasuredChild {
|
||||
cross,
|
||||
natural_cross,
|
||||
main: measured_main,
|
||||
is_flex,
|
||||
});
|
||||
@@ -902,12 +932,24 @@ fn layout_container_children(
|
||||
} else {
|
||||
measured.main
|
||||
};
|
||||
// For non-stretch alignment, use the child's natural cross size; otherwise stretch.
|
||||
// align_self on the child overrides the parent's align_items for this child.
|
||||
let effective_align = child.style.align_self.unwrap_or(element.style.align_items);
|
||||
let actual_cross = measured.natural_cross.unwrap_or(measured.cross);
|
||||
let cross_origin = {
|
||||
let base = cross_axis_origin(content, element.style.direction);
|
||||
match effective_align {
|
||||
AlignItems::Stretch | AlignItems::Start => base,
|
||||
AlignItems::Center => base + (available_cross - actual_cross) * 0.5,
|
||||
AlignItems::End => base + available_cross - actual_cross,
|
||||
}
|
||||
};
|
||||
let child_rect = child_rect(
|
||||
content,
|
||||
cross_origin,
|
||||
element.style.direction,
|
||||
cursor,
|
||||
child_main.max(0.0),
|
||||
measured.cross,
|
||||
actual_cross,
|
||||
);
|
||||
children.push(layout_element(
|
||||
child,
|
||||
@@ -1865,16 +1907,23 @@ fn main_axis_origin(rect: Rect, direction: FlexDirection) -> f32 {
|
||||
}
|
||||
}
|
||||
|
||||
fn cross_axis_origin(content: Rect, direction: FlexDirection) -> f32 {
|
||||
match direction {
|
||||
FlexDirection::Row => content.origin.y,
|
||||
FlexDirection::Column => content.origin.x,
|
||||
}
|
||||
}
|
||||
|
||||
fn child_rect(
|
||||
content: Rect,
|
||||
cross_origin: f32,
|
||||
direction: FlexDirection,
|
||||
main_origin: f32,
|
||||
main_size: f32,
|
||||
cross_size: f32,
|
||||
) -> Rect {
|
||||
match direction {
|
||||
FlexDirection::Row => Rect::new(main_origin, content.origin.y, main_size, cross_size),
|
||||
FlexDirection::Column => Rect::new(content.origin.x, main_origin, cross_size, main_size),
|
||||
FlexDirection::Row => Rect::new(main_origin, cross_origin, main_size, cross_size),
|
||||
FlexDirection::Column => Rect::new(cross_origin, main_origin, cross_size, main_size),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user