diff --git a/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs index ef04a61fb..17314d482 100644 --- a/src/compute/grid/explicit_grid.rs +++ b/src/compute/grid/explicit_grid.rs @@ -7,7 +7,6 @@ use crate::resolve::ResolveOrZero; use crate::style::{GridTrackRepetition, LengthPercentage, NonRepeatedTrackSizingFunction, Style, TrackSizingFunction}; use crate::style_helpers::TaffyAuto; use crate::sys::{GridTrackVec, Vec}; -use core::cmp::{max, min}; /// Compute the number of rows and columns in the explicit grid pub(crate) fn compute_explicit_grid_size_in_axis(style: &Style, axis: AbsoluteAxis) -> u16 { @@ -191,15 +190,15 @@ pub(super) fn initialize_grid_tracks( tracks.push(GridTrack::gutter(gap)); // Create negative implicit tracks - if auto_tracks.is_empty() { - let iter = core::iter::repeat(NonRepeatedTrackSizingFunction::AUTO); - create_implicit_tracks(tracks, counts.negative_implicit, iter, gap) - } else { - let max_count = max(auto_tracks.len(), counts.negative_implicit as usize); - let min_count = min(auto_tracks.len(), counts.negative_implicit as usize); - let offset = max_count % min_count; - let iter = auto_tracks.iter().copied().cycle().skip(offset); - create_implicit_tracks(tracks, counts.negative_implicit, iter, gap) + if counts.negative_implicit > 0 { + if auto_tracks.is_empty() { + let iter = core::iter::repeat(NonRepeatedTrackSizingFunction::AUTO); + create_implicit_tracks(tracks, counts.negative_implicit, iter, gap) + } else { + let offset = auto_tracks.len() - (counts.negative_implicit as usize % auto_tracks.len()); + let iter = auto_tracks.iter().copied().cycle().skip(offset); + create_implicit_tracks(tracks, counts.negative_implicit, iter, gap) + } } let mut current_track_index = (counts.negative_implicit) as usize; diff --git a/src/compute/grid/placement.rs b/src/compute/grid/placement.rs index d02e7af8e..33350dab0 100644 --- a/src/compute/grid/placement.rs +++ b/src/compute/grid/placement.rs @@ -113,9 +113,11 @@ pub(super) fn place_grid_items<'a, ChildIter>( // 4. Position the remaining grid items // (which either have definite position only in the secondary axis or indefinite positions in both axis) - let x_neg_tracks = cell_occupancy_matrix.track_counts(AbsoluteAxis::Horizontal).negative_implicit as i16; - let y_neg_tracks = cell_occupancy_matrix.track_counts(AbsoluteAxis::Vertical).negative_implicit as i16; - let grid_start_position = (OriginZeroLine(-x_neg_tracks), OriginZeroLine(-y_neg_tracks)); + let primary_axis = grid_auto_flow.primary_axis(); + let secondary_axis = primary_axis.other_axis(); + let primary_neg_tracks = cell_occupancy_matrix.track_counts(primary_axis).negative_implicit as i16; + let secondary_neg_tracks = cell_occupancy_matrix.track_counts(secondary_axis).negative_implicit as i16; + let grid_start_position = (OriginZeroLine(-primary_neg_tracks), OriginZeroLine(-secondary_neg_tracks)); let mut grid_position = grid_start_position; let mut idx = 0; children_iter() diff --git a/src/compute/grid/types/cell_occupancy.rs b/src/compute/grid/types/cell_occupancy.rs index 35b3d5cef..cf006e75c 100644 --- a/src/compute/grid/types/cell_occupancy.rs +++ b/src/compute/grid/types/cell_occupancy.rs @@ -91,10 +91,9 @@ impl CellOccupancyMatrix { fn expand_to_fit_range(&mut self, row_range: Range, col_range: Range) { // Calculate number of rows and columns missing to accomodate ranges (if any) let req_negative_rows = min(row_range.start, 0); - let req_positive_rows = max(row_range.end - self.rows.explicit as i16 - self.rows.positive_implicit as i16, 0); + let req_positive_rows = max(row_range.end - self.rows.len() as i16, 0); let req_negative_cols = min(col_range.start, 0); - let req_positive_cols = - max(col_range.end - self.columns.explicit as i16 - self.columns.positive_implicit as i16, 0); + let req_positive_cols = max(col_range.end - self.columns.len() as i16, 0); let old_row_count = self.rows.len(); let old_col_count = self.columns.len(); diff --git a/test_fixtures/grid_auto_columns.html b/test_fixtures/grid_auto_columns.html new file mode 100644 index 000000000..7e717bef0 --- /dev/null +++ b/test_fixtures/grid_auto_columns.html @@ -0,0 +1,24 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/test_fixtures/grid_auto_rows.html b/test_fixtures/grid_auto_rows.html new file mode 100644 index 000000000..19f55d5bc --- /dev/null +++ b/test_fixtures/grid_auto_rows.html @@ -0,0 +1,24 @@ + + + + + + + Test description + + + + +
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/tests/generated/grid_auto_columns.rs b/tests/generated/grid_auto_columns.rs new file mode 100644 index 000000000..40e498581 --- /dev/null +++ b/tests/generated/grid_auto_columns.rs @@ -0,0 +1,82 @@ +#[test] +fn grid_auto_columns() { + use slotmap::Key; + #[allow(unused_imports)] + use taffy::{layout::Layout, prelude::*}; + let mut taffy = taffy::Taffy::new(); + let node0 = taffy + .new_leaf(taffy::style::Style { + grid_column: taffy::geometry::Line { start: line(-3i16), end: taffy::style::GridPlacement::Auto }, + ..Default::default() + }) + .unwrap(); + let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node = taffy + .new_with_children( + taffy::style::Style { + display: taffy::style::Display::Grid, + grid_template_rows: vec![points(100f32)], + grid_template_columns: vec![points(40f32)], + grid_auto_columns: vec![points(10f32), points(20f32), points(30f32)], + grid_auto_flow: taffy::style::GridAutoFlow::Column, + ..Default::default() + }, + &[node0, node1, node2, node3, node4, node5, node6, node7], + ) + .unwrap(); + taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap(); + println!("\nComputed tree:"); + taffy::debug::print_tree(&taffy, node); + println!(); + let Layout { size, location, .. } = taffy.layout(node).unwrap(); + assert_eq!(size.width, 190f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 190f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node0).unwrap(); + assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 30f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node1).unwrap(); + assert_eq!(size.width, 40f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 40f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 100f32, size.height); + assert_eq!(location.x, 30f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 30f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node2).unwrap(); + assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 10f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 100f32, size.height); + assert_eq!(location.x, 70f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 70f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node3).unwrap(); + assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 20f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 100f32, size.height); + assert_eq!(location.x, 80f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 80f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node4).unwrap(); + assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 30f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 100f32, size.height); + assert_eq!(location.x, 100f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 100f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node5).unwrap(); + assert_eq!(size.width, 10f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 10f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 100f32, size.height); + assert_eq!(location.x, 130f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 130f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node6).unwrap(); + assert_eq!(size.width, 20f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 20f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 100f32, size.height); + assert_eq!(location.x, 140f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 140f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node7).unwrap(); + assert_eq!(size.width, 30f32, "width of node {:?}. Expected {}. Actual {}", node7.data(), 30f32, size.width); + assert_eq!(size.height, 100f32, "height of node {:?}. Expected {}. Actual {}", node7.data(), 100f32, size.height); + assert_eq!(location.x, 160f32, "x of node {:?}. Expected {}. Actual {}", node7.data(), 160f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node7.data(), 0f32, location.y); +} diff --git a/tests/generated/grid_auto_rows.rs b/tests/generated/grid_auto_rows.rs new file mode 100644 index 000000000..5019a9878 --- /dev/null +++ b/tests/generated/grid_auto_rows.rs @@ -0,0 +1,81 @@ +#[test] +fn grid_auto_rows() { + use slotmap::Key; + #[allow(unused_imports)] + use taffy::{layout::Layout, prelude::*}; + let mut taffy = taffy::Taffy::new(); + let node0 = taffy + .new_leaf(taffy::style::Style { + grid_row: taffy::geometry::Line { start: line(-4i16), end: taffy::style::GridPlacement::Auto }, + ..Default::default() + }) + .unwrap(); + let node1 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node2 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node3 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node4 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node5 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node6 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node7 = taffy.new_leaf(taffy::style::Style { ..Default::default() }).unwrap(); + let node = taffy + .new_with_children( + taffy::style::Style { + display: taffy::style::Display::Grid, + grid_template_rows: vec![points(40f32)], + grid_template_columns: vec![points(100f32)], + grid_auto_rows: vec![points(10f32), points(20f32), points(30f32)], + ..Default::default() + }, + &[node0, node1, node2, node3, node4, node5, node6, node7], + ) + .unwrap(); + taffy.compute_layout(node, taffy::geometry::Size::MAX_CONTENT).unwrap(); + println!("\nComputed tree:"); + taffy::debug::print_tree(&taffy, node); + println!(); + let Layout { size, location, .. } = taffy.layout(node).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node.data(), 100f32, size.width); + assert_eq!(size.height, 180f32, "height of node {:?}. Expected {}. Actual {}", node.data(), 180f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node0).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node0.data(), 100f32, size.width); + assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node0.data(), 20f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.x); + assert_eq!(location.y, 0f32, "y of node {:?}. Expected {}. Actual {}", node0.data(), 0f32, location.y); + let Layout { size, location, .. } = taffy.layout(node1).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node1.data(), 100f32, size.width); + assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node1.data(), 30f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node1.data(), 0f32, location.x); + assert_eq!(location.y, 20f32, "y of node {:?}. Expected {}. Actual {}", node1.data(), 20f32, location.y); + let Layout { size, location, .. } = taffy.layout(node2).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node2.data(), 100f32, size.width); + assert_eq!(size.height, 40f32, "height of node {:?}. Expected {}. Actual {}", node2.data(), 40f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node2.data(), 0f32, location.x); + assert_eq!(location.y, 50f32, "y of node {:?}. Expected {}. Actual {}", node2.data(), 50f32, location.y); + let Layout { size, location, .. } = taffy.layout(node3).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node3.data(), 100f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node3.data(), 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node3.data(), 0f32, location.x); + assert_eq!(location.y, 90f32, "y of node {:?}. Expected {}. Actual {}", node3.data(), 90f32, location.y); + let Layout { size, location, .. } = taffy.layout(node4).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node4.data(), 100f32, size.width); + assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node4.data(), 20f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node4.data(), 0f32, location.x); + assert_eq!(location.y, 100f32, "y of node {:?}. Expected {}. Actual {}", node4.data(), 100f32, location.y); + let Layout { size, location, .. } = taffy.layout(node5).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node5.data(), 100f32, size.width); + assert_eq!(size.height, 30f32, "height of node {:?}. Expected {}. Actual {}", node5.data(), 30f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node5.data(), 0f32, location.x); + assert_eq!(location.y, 120f32, "y of node {:?}. Expected {}. Actual {}", node5.data(), 120f32, location.y); + let Layout { size, location, .. } = taffy.layout(node6).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node6.data(), 100f32, size.width); + assert_eq!(size.height, 10f32, "height of node {:?}. Expected {}. Actual {}", node6.data(), 10f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node6.data(), 0f32, location.x); + assert_eq!(location.y, 150f32, "y of node {:?}. Expected {}. Actual {}", node6.data(), 150f32, location.y); + let Layout { size, location, .. } = taffy.layout(node7).unwrap(); + assert_eq!(size.width, 100f32, "width of node {:?}. Expected {}. Actual {}", node7.data(), 100f32, size.width); + assert_eq!(size.height, 20f32, "height of node {:?}. Expected {}. Actual {}", node7.data(), 20f32, size.height); + assert_eq!(location.x, 0f32, "x of node {:?}. Expected {}. Actual {}", node7.data(), 0f32, location.x); + assert_eq!(location.y, 160f32, "y of node {:?}. Expected {}. Actual {}", node7.data(), 160f32, location.y); +} diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs index 05c7f1243..a9806b4df 100644 --- a/tests/generated/mod.rs +++ b/tests/generated/mod.rs @@ -451,6 +451,8 @@ mod grid_aspect_ratio_overriden_by_explicit_sizes; #[cfg(feature = "grid")] mod grid_aspect_ratio_overriden_by_explicit_sizes_flex; #[cfg(feature = "grid")] +mod grid_auto_columns; +#[cfg(feature = "grid")] mod grid_auto_columns_fixed_width; #[cfg(feature = "grid")] mod grid_auto_fill_fixed_size; @@ -459,6 +461,8 @@ mod grid_auto_fill_with_empty_auto_track; #[cfg(feature = "grid")] mod grid_auto_fit_with_empty_auto_track; #[cfg(feature = "grid")] +mod grid_auto_rows; +#[cfg(feature = "grid")] mod grid_auto_single_item; #[cfg(feature = "grid")] mod grid_auto_single_item_fixed_width;