Semántico sayk'uy · 11
src/compute/morphorm.rs
- silq'uyninpi t'ikrakurqan struct ChildNode pub
- ukhunpi t'ikrakurqan fn compute pub
diff --git a/src/compute/morphorm.rs b/src/compute/morphorm.rs
index 5f61227d4..6d9136a78 100644
--- a/src/compute/morphorm.rs
+++ b/src/compute/morphorm.rs
@@ -46,11 +46,16 @@ pub struct ChildNode {
node: NodeId,
// Whether the child is in flow or not
is_in_flow: bool,
+ is_first: bool,
+ is_last: bool,
// The index of the node.
index: usize,
style: Style,
+ size: Size<f32>,
+
+ spacing: Rect<f32>,
// // The stretch factor of the node.
// stretch_factor: Size<f32>,
@@ -91,33 +96,16 @@ pub fn compute(
available_space: Size<AvailableSpace>,
run_mode: RunMode,
) -> SizeBaselinesAndMargins {
-
// TODO: Min/Max constraints for space and size
// The layout type of the node. Determines the main and cross axes of the children.
- let style = tree.style(node).clone();
- // let layout_type = style.flex_direction;
- let is_row = style.flex_direction.is_row();
-
- // // The desired main-axis and cross-axis sizes of the node.
- // let main = node.main(store, parent_layout_type);
- // let cross = node.cross(store, parent_layout_type);
-
- // // Compute main-axis size.
- // let mut computed_main = match main {
- // Pixels(val) => val,
+ let container_style = tree.style(node).clone();
+ let dir = container_style.flex_direction;
+ let is_row = dir.is_row();
- // Percentage(val) => (parent_main * (val / 100.0)).round(),
-
- // Stretch(_) => parent_main,
-
- // Auto => 0.0,
- // };
-
- let min_size = style.min_size.maybe_resolve(parent_size);
- let max_size = style.max_size.maybe_resolve(parent_size);
- let clamped_style_size =
- style.size.maybe_resolve(parent_size).maybe_clamp(min_size, max_size);
+ let min_size = container_style.min_size.maybe_resolve(parent_size);
+ let max_size = container_style.max_size.maybe_resolve(parent_size);
+ let clamped_style_size = container_style.size.maybe_resolve(parent_size).maybe_clamp(min_size, max_size);
// If both min and max in a given axis are set and max <= min then this determines the size in that axis
let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
@@ -134,42 +122,107 @@ pub fn compute(
}
}
-
-
-
- let in_flow_children = tree.children(node)
+ let in_flow_children: Vec<ChildNode> = tree
+ .children(node)
.map(|child| (child, tree.style(*child)))
.filter(|(_, style)| style.position != Position::Absolute)
.filter(|(_, style)| style.display != Display::None)
.enumerate()
.map(|(index, (child, child_style))| {
+ ChildNode {
+ node,
+ is_first: false, // Set later
+ is_last: false, // Set later
+ is_in_flow: child_style.position != Position::Absolute,
+ index,
+ style: child_style.clone(),
+ size: Size::zero(), // Set later
+ spacing: Rect::zero(), // Set later
+ }
+ })
+ .collect();
- let child_min_size = child_style.min_size.maybe_resolve(parent_size);
- let max_size = style.max_size.maybe_resolve(parent_size);
- let clamped_style_size =
- style.size.maybe_resolve(parent_size).maybe_clamp(min_size, max_size);
-
- // If both min and max in a given axis are set and max <= min then this determines the size in that axis
- let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
- (Some(min), Some(max)) if max <= min => Some(min),
- _ => None,
- });
- let styled_based_known_dimensions = min_max_definite_size.or(clamped_style_size);
-
- let content_size = if child_style.size.width == Dimension::Auto || child_style.size.height == Dimension::Auto {
- tree.measure_child_size(node, known_dimensions, parent_size, available_space, SizingMode::InherentSize, Line::NONE)
+ // Set is_first and is_last properties on the first and last children
+ let in_flow_child_count = in_flow_children.len();
+ in_flow_children[0].is_first = true;
+ in_flow_children[in_flow_children.len() - 1].is_last = true;
+
+
+ // Compute size and spacing for each child
+ let space_around = container_style.spacing_around.resolve_or_zero(parent_size);
+ let space_between = container_style.spacing_between.resolve_or_zero(parent_size);
+ for child in in_flow_children.iter_mut() {
+ let child_min_size = child.style.min_size.maybe_resolve(parent_size);
+ let max_size = child.style.max_size.maybe_resolve(parent_size);
+ let clamped_style_size = child.style.size.maybe_resolve(parent_size).maybe_clamp(min_size, max_size);
+
+ // If both min and max in a given axis are set and max <= min then this determines the size in that axis
+ let min_max_definite_size = min_size.zip_map(max_size, |min, max| match (min, max) {
+ (Some(min), Some(max)) if max <= min => Some(min),
+ _ => None,
+ });
+ let child_style_based_known_dimensions = min_max_definite_size.or(clamped_style_size);
+
+ // Compute content size if size is not already known and the item has an "auto" dimension
+ let has_auto_dimension =
+ child.style.size.width == Dimension::Auto || child.style.size.height == Dimension::Auto;
+ let content_size: Size<Option<f32>> =
+ if !child_style_based_known_dimensions.both_axis_defined() && has_auto_dimension {
+ GenericAlgorithm::measure_size(
+ tree,
+ node,
+ known_dimensions,
+ parent_size,
+ available_space,
+ SizingMode::InherentSize,
+ )
+ .map(Some)
} else {
- Size::zero()
+ child_style_based_known_dimensions
};
- ChildNode {
- node,
- is_in_flow: child_style.position != Position::Absolute
- index,
- style: child_style.clone(),
- }
- })
- .collect();
+ child.size = child_style_based_known_dimensions.or(content_size).unwrap_or(Size::zero()).maybe_clamp(min_size, max_size);
+
+ let default_spacing = {
+ let mut space = space_around;
+ if !child.is_first {
+ space.set_main_start(dir, space_between.main(dir));
+ }
+ if !child.is_last {
+ space.set_main_end(dir, 0.0);
+ }
+ };
+
+ let resolved_margin = child.style.margin.map(|m| m.resolve_to_option(0.0));
+ let outer_spacing = resolved_margin.unwrap_or(space_around);
+
+ }
+
+ // Compute space used by the content size of each no in each axis
+ let main_axis_used_space: f32 =
+ in_flow_children.iter().map(|child| child.size.main(dir) + child.spacing.main_axis_sum(dir)).sum();
+ let cross_axis_used_space: f32 = in_flow_children
+ .iter()
+ .map(|child| child.size.cross(dir) + child.spacing.cross_axis_sum(dir))
+ .max_by(|a, b| a.total_cmp(b))
+ .unwrap_or(0.0);
+ let used_space = {
+ let mut space = Size::zero();
+ space.set_main(dir, main_axis_used_space);
+ space.set_cross(dir, cross_axis_used_space);
+ space
+ };
+ let container_size = styled_based_known_dimensions.unwrap_or(used_space);
+
+ // Return early if we're only computing container size
+ if run_mode == RunMode::ComputeSize {
+ return container_size.into();
+ }
+
+ let free_space = container_size - used_space;
+
+ // TODO perform stretch sizing
+ // TODO position nodes
// Sum of all non-flexible space and size on the main-axis of the node.
@@ -504,20 +557,20 @@ pub fn compute(
child.cross_remainder = desired_cross - actual_cross;
// if cross == Units::Auto && num_children != 0 {
- let size = layout(child.node, layout_type, parent_main, actual_cross, cache, tree, store);
+ let size = layout(child.node, layout_type, parent_main, actual_cross, cache, tree, store);
// println!("size: {:?}", size);
// } else {
- // At this stage stretch nodes on the cross-axis can only be the determined size so we can set it directly
- // in the cache without needing to call layout again.
- // match layout_type {
- // LayoutType::Row => {
- // cache.set_height(child.node.key(), actual_cross);
- // }
-
- // LayoutType::Column => {
- // cache.set_width(child.node.key(), actual_cross);
- // }
- // }
+ // At this stage stretch nodes on the cross-axis can only be the determined size so we can set it directly
+ // in the cache without needing to call layout again.
+ // match layout_type {
+ // LayoutType::Row => {
+ // cache.set_height(child.node.key(), actual_cross);
+ // }
+
+ // LayoutType::Column => {
+ // cache.set_width(child.node.key(), actual_cross);
+ // }
+ // }
// }
}
@@ -609,5 +662,4 @@ pub fn compute(
// Return the computed size, propagating it back up the tree.
Size { main: computed_main, cross: computed_cross }.into()
-
}
diff --git a/src/geometry.rs b/src/geometry.rs
index 006a21491..bcd8a686b 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -1,10 +1,9 @@
//! Geometric primitives useful for layout
-
use crate::style::Dimension;
use crate::util::sys::f32_max;
use core::ops::{Add, Sub};
-#[cfg(feature = "flexbox")]
+#[cfg(any(feature = "flexbox", feature = "morphorm"))]
use crate::style::FlexDirection;
/// The simple absolute horizontal and vertical axis
@@ -244,6 +243,15 @@ where
}
}
+ /// Set the `start` or `top` value of the [`Rect`], from the perspective of the main layout axis
+ pub(crate) fn set_main_start(&self, direction: FlexDirection, value: T) {
+ if direction.is_row() {
+ self.left = value;
+ } else {
+ self.top = value;
+ }
+ }
+
/// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
#[cfg(feature = "flexbox")]
pub(crate) fn main_end(&self, direction: FlexDirection) -> T {
@@ -254,6 +262,15 @@ where
}
}
+ /// Set the `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
+ pub(crate) fn set_main_end(&self, direction: FlexDirection, value: T) {
+ if direction.is_row() {
+ self.right = value;
+ } else {
+ self.bottom = value;
+ }
+ }
+
/// The `start` or `top` value of the [`Rect`], from the perspective of the cross layout axis
#[cfg(feature = "flexbox")]
pub(crate) fn cross_start(&self, direction: FlexDirection) -> T {
@@ -264,6 +281,16 @@ where
}
}
+
+ /// Set the `start` or `top` value of the [`Rect`], from the perspective of the cross layout axis
+ pub(crate) fn set_cross_start(&self, direction: FlexDirection, value: T) {
+ if direction.is_row() {
+ self.top = value;
+ } else {
+ self.left = value;
+ }
+ }
+
/// The `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
#[cfg(feature = "flexbox")]
pub(crate) fn cross_end(&self, direction: FlexDirection) -> T {
@@ -273,6 +300,16 @@ where
self.right
}
}
+
+
+ /// Set the `end` or `bottom` value of the [`Rect`], from the perspective of the main layout axis
+ pub(crate) fn set_cross_end(&self, direction: FlexDirection, value: T) {
+ if direction.is_row() {
+ self.bottom = value;
+ } else {
+ self.right = value;
+ }
+ }
}
impl Rect<f32> {
@@ -286,6 +323,28 @@ impl Rect<f32> {
}
}
+impl<T> Rect<Option<T>> {
+ /// Performs Option::unwrap_or on each component separately
+ pub fn unwrap_or(self, alt: Rect<T>) -> Rect<T> {
+ Rect {
+ left: self.left.unwrap_or(alt.left),
+ right: self.right.unwrap_or(alt.right),
+ top: self.top.unwrap_or(alt.top),
+ bottom: self.bottom.unwrap_or(alt.bottom),
+ }
+ }
+
+ /// Performs Option::or on each component separately
+ pub fn or(self, alt: Rect<Option<T>>) -> Rect<Option<T>> {
+ Rect {
+ left: self.left.or(alt.left),
+ right: self.right.or(alt.right),
+ top: self.top.or(alt.top),
+ bottom: self.bottom.or(alt.bottom),
+ }
+ }
+}
+
/// An abstract "line". Represents any type that has a start and an end
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
diff --git a/src/style/mod.rs b/src/style/mod.rs
index 1ad9c892b..6044530a7 100644
--- a/src/style/mod.rs
+++ b/src/style/mod.rs
@@ -284,7 +284,10 @@ pub struct Style {
// Morphorm container properties
/// Sets the default spacing *around* the group of all children of a morphorm container
#[cfg(feature = "morphorm")]
- pub child_spacing: Rect<LengthPercentageAuto>,
+ pub spacing_around: Rect<LengthPercentageAuto>,
+ /// Sets the default spacing *between* the group of all children of a morphorm container
+ #[cfg(feature = "morphorm")]
+ pub spacing_between: Size<LengthPercentageAuto>,
// Morphorm child properties
/// Sets the minimum margin for child
@@ -353,7 +356,9 @@ impl Style {
grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
#[cfg(feature = "morphorm")]
- child_spacing: Rect::zero(),
+ spacing_around: Rect::zero(),
+ #[cfg(feature = "morphorm")]
+ spacing_between: Size::zero(),
#[cfg(feature = "morphorm")]
min_margin: Rect::zero(),
#[cfg(feature = "morphorm")]
@@ -436,7 +441,9 @@ mod tests {
grid_column: Line { start: GridPlacement::Auto, end: GridPlacement::Auto },
#[cfg(feature = "morphorm")]
- child_spacing: Rect::zero(),
+ spacing_around: Rect::zero(),
+ #[cfg(feature = "morphorm")]
+ spacing_between: Size::zero(),
#[cfg(feature = "morphorm")]
min_margin: Rect::zero(),
#[cfg(feature = "morphorm")]