Merge pull request #6794 from penpot/alotor-wasm-fix-grid-fr

🐛 Fix problem with fr allocation
This commit is contained in:
Aitor Moreno 2025-06-26 14:39:42 +02:00 committed by GitHub
commit 29016cef49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 93 additions and 72 deletions

View file

@ -467,15 +467,15 @@
row-tracks (set-flex-multi-span parent row-tracks children-map shape-cells bounds objects :row) row-tracks (set-flex-multi-span parent row-tracks children-map shape-cells bounds objects :row)
;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size ;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size
free-column-space (max 0 (- bound-width (+ column-total-size-nofr column-total-gap))) fr-column-space (max 0 (- bound-width (+ column-total-size-nofr column-total-gap)))
free-row-space (max 0 (- bound-height (+ row-total-size-nofr row-total-gap))) fr-row-space (max 0 (- bound-height (+ row-total-size-nofr row-total-gap)))
;; Get the minimum values for fr's ;; Get the minimum values for fr's
min-column-fr (min-fr-value column-tracks) min-column-fr (min-fr-value column-tracks)
min-row-fr (min-fr-value row-tracks) min-row-fr (min-fr-value row-tracks)
column-fr (if auto-width? min-column-fr (mth/finite (/ free-column-space column-frs) 0)) column-fr (if auto-width? min-column-fr (mth/finite (/ fr-column-space column-frs) 0))
row-fr (if auto-height? min-row-fr (mth/finite (/ free-row-space row-frs) 0)) row-fr (if auto-height? min-row-fr (mth/finite (/ fr-row-space row-frs) 0))
column-tracks (set-fr-value column-tracks column-fr auto-width?) column-tracks (set-fr-value column-tracks column-fr auto-width?)
row-tracks (set-fr-value row-tracks row-fr auto-height?) row-tracks (set-fr-value row-tracks row-fr auto-height?)
@ -484,13 +484,13 @@
column-total-size (tracks-total-size column-tracks) column-total-size (tracks-total-size column-tracks)
row-total-size (tracks-total-size row-tracks) row-total-size (tracks-total-size row-tracks)
free-column-space (max 0 (if auto-width? 0 (- bound-width (+ column-total-size column-total-gap)))) auto-column-space (max 0 (if auto-width? 0 (- bound-width (+ column-total-size column-total-gap))))
free-row-space (max 0 (if auto-height? 0 (- bound-height (+ row-total-size row-total-gap)))) auto-row-space (max 0 (if auto-height? 0 (- bound-height (+ row-total-size row-total-gap))))
column-autos (tracks-total-autos column-tracks) column-autos (tracks-total-autos column-tracks)
row-autos (tracks-total-autos row-tracks) row-autos (tracks-total-autos row-tracks)
column-add-auto (/ free-column-space column-autos) column-add-auto (/ auto-column-space column-autos)
row-add-auto (/ free-row-space row-autos) row-add-auto (/ auto-row-space row-autos)
column-tracks (cond-> column-tracks column-tracks (cond-> column-tracks
(= :stretch (:layout-justify-content parent)) (= :stretch (:layout-justify-content parent))

View file

@ -51,6 +51,12 @@ pub fn calculate_tracks(
layout_bounds.height() - layout_data.padding_top - layout_data.padding_bottom layout_bounds.height() - layout_data.padding_top - layout_data.padding_bottom
}; };
let auto_layout = if is_column {
shape.is_layout_horizontal_auto()
} else {
shape.is_layout_vertical_auto()
};
let grid_tracks = if is_column { let grid_tracks = if is_column {
&grid_data.columns &grid_data.columns
} else { } else {
@ -60,8 +66,14 @@ pub fn calculate_tracks(
let mut tracks = init_tracks(grid_tracks, layout_size); let mut tracks = init_tracks(grid_tracks, layout_size);
set_auto_base_size(is_column, &mut tracks, cells, shapes, bounds); set_auto_base_size(is_column, &mut tracks, cells, shapes, bounds);
set_auto_multi_span(is_column, &mut tracks, cells, shapes, bounds); set_auto_multi_span(is_column, &mut tracks, cells, shapes, bounds);
set_flex_multi_span(is_column, &mut tracks, cells, shapes, bounds); set_flex_multi_span(is_column, layout_data, &mut tracks, cells, shapes, bounds);
set_fr_value(is_column, shape, layout_data, &mut tracks, layout_size); set_fr_value(
is_column,
layout_data,
&mut tracks,
layout_size,
auto_layout,
);
stretch_tracks(is_column, shape, layout_data, &mut tracks, layout_size); stretch_tracks(is_column, shape, layout_data, &mut tracks, layout_size);
assign_anchors(is_column, layout_data, layout_bounds, &mut tracks); assign_anchors(is_column, layout_data, layout_bounds, &mut tracks);
tracks tracks
@ -230,6 +242,7 @@ fn set_auto_multi_span(
// Adjust multi-spaned cells with flex columns // Adjust multi-spaned cells with flex columns
fn set_flex_multi_span( fn set_flex_multi_span(
column: bool, column: bool,
layout_data: &LayoutData,
tracks: &mut [TrackData], tracks: &mut [TrackData],
cells: &[GridCell], cells: &[GridCell],
shapes: &HashMap<Uuid, &mut Shape>, shapes: &HashMap<Uuid, &mut Shape>,
@ -257,6 +270,12 @@ fn set_flex_multi_span(
} }
}); });
let gap_value = if column {
layout_data.column_gap
} else {
layout_data.row_gap
};
// Retrieve the value that we need to distribute and the number of frs // Retrieve the value that we need to distribute and the number of frs
for cell in selected_cells { for cell in selected_cells {
let Some(child) = cell.shape.and_then(|id| shapes.get(&id)) else { let Some(child) = cell.shape.and_then(|id| shapes.get(&id)) else {
@ -264,25 +283,20 @@ fn set_flex_multi_span(
}; };
// Retrieve the value we need to distribute (fixed cell size minus gaps) // Retrieve the value we need to distribute (fixed cell size minus gaps)
let mut dist = min_size(column, child, bounds);
let mut num_flex = 0.0;
let mut num_auto = 0;
let (start, end) = track_index(column, cell); let (start, end) = track_index(column, cell);
let gaps = (end - start - 1) as f32 * gap_value;
let mut dist = min_size(column, child, bounds) - gaps;
let mut num_flex = 0.0;
// Distribute the size between the tracks that already have a set value // Distribute the size between the tracks that already have a set value
for track in tracks[start..end].iter() { for track in tracks[start..end].iter() {
dist -= track.size;
match track.track_type { match track.track_type {
GridTrackType::Flex => { GridTrackType::Flex => {
num_flex += track.value; num_flex += track.value;
num_auto += 1;
} }
GridTrackType::Auto => { _ => {
num_auto += 1; dist -= track.size;
} }
_ => {}
} }
} }
@ -291,37 +305,15 @@ fn set_flex_multi_span(
continue; continue;
} }
let rest = dist / num_flex; let alloc = dist / num_flex;
// Distribute the space between flex tracks in proportion to the division // Distribute the space between flex tracks in proportion to the division
for track in tracks[start..end].iter_mut() { for track in tracks[start..end].iter_mut() {
if track.track_type == GridTrackType::Flex { if track.track_type == GridTrackType::Flex {
let new_size = f32::min(track.size + rest, track.max_size); let new_size = alloc.clamp(track.size, track.max_size);
let aloc = new_size - track.size; let aloc = new_size - track.size;
dist -= aloc; dist -= aloc;
track.size += aloc; track.size = new_size;
}
}
// Distribute the space between auto tracks if any
while dist > MIN_SIZE && num_auto > 0 {
let rest = dist / num_auto as f32;
for track in tracks[start..end].iter_mut() {
if track.track_type == GridTrackType::Auto
|| track.track_type == GridTrackType::Flex
{
let new_size = if track.size + rest < track.max_size {
track.size + rest
} else {
num_auto -= 1;
track.max_size
};
let aloc = new_size - track.size;
dist -= aloc;
track.size += aloc;
}
} }
} }
} }
@ -330,10 +322,10 @@ fn set_flex_multi_span(
// Calculate the `fr` unit and adjust the size // Calculate the `fr` unit and adjust the size
fn set_fr_value( fn set_fr_value(
column: bool, column: bool,
shape: &Shape,
layout_data: &LayoutData, layout_data: &LayoutData,
tracks: &mut [TrackData], tracks: &mut [TrackData],
layout_size: f32, layout_size: f32,
auto_layout: bool,
) { ) {
let tot_gap: f32 = if column { let tot_gap: f32 = if column {
layout_data.column_gap * (tracks.len() as f32 - 1.0) layout_data.column_gap * (tracks.len() as f32 - 1.0)
@ -341,41 +333,65 @@ fn set_fr_value(
layout_data.row_gap * (tracks.len() as f32 - 1.0) layout_data.row_gap * (tracks.len() as f32 - 1.0)
}; };
// Total size already used let mut tot_size_nofr = tot_gap;
let tot_size: f32 = tracks let mut tot_frs = 0.0;
.iter() let mut cur_fr_value = 0.0;
.filter(|t| t.track_type != GridTrackType::Flex)
.map(|t| t.size)
.sum::<f32>()
+ tot_gap;
let tot_frs: f32 = tracks for t in tracks.iter() {
.iter() if t.track_type == GridTrackType::Flex {
.filter(|t| t.track_type == GridTrackType::Flex) tot_frs += t.value;
.map(|t| t.value) cur_fr_value = f32::max(t.size / t.value, cur_fr_value);
.sum(); } else {
tot_size_nofr += t.size;
}
}
let cur_fr_size = tracks let fr_space = f32::max(0.0, layout_size - tot_size_nofr);
.iter()
.filter(|t| t.track_type == GridTrackType::Flex)
.map(|t| t.size / t.value)
.reduce(f32::max)
.unwrap_or(0.0);
// Divide the space between FRS let mut fr_value = if auto_layout {
let fr = if column && shape.is_layout_horizontal_auto() // If auto_layout we assign the max fr
|| !column && shape.is_layout_vertical_auto() cur_fr_value
{
cur_fr_size
} else { } else {
f32::max(cur_fr_size, (layout_size - tot_size) / tot_frs) fr_space / tot_frs
}; };
// Assign the space to the FRS if !auto_layout {
loop {
// While there is still tracks that can take more size
let mut pending = fr_space;
let mut free_frs = 0;
for t in tracks.iter() {
if t.track_type == GridTrackType::Flex {
// Use the current fr size
let current = t.value * fr_value;
if t.size > current {
// If it's not enough psace to allocate, this is full. Cannot grow anymore.
pending -= t.size;
} else {
// Otherwise, this track can still grow
free_frs += 1;
pending -= current;
}
}
}
// We finish when we cannot reduce the tracks more or we've allocated all
// the space
if free_frs == 0 || pending >= 0.0 {
break;
}
fr_value += pending / free_frs as f32;
}
}
// Assign the fr_value to the flex tracks
tracks tracks
.iter_mut() .iter_mut()
.filter(|t| t.track_type == GridTrackType::Flex) .filter(|t| t.track_type == GridTrackType::Flex)
.for_each(|t| t.size = f32::min(fr * t.value, t.max_size)); .for_each(|t| t.size = (fr_value * t.value).clamp(t.size, t.max_size));
} }
fn stretch_tracks( fn stretch_tracks(
@ -411,6 +427,11 @@ fn stretch_tracks(
.count() as f32; .count() as f32;
let free_space = layout_size - tot_size; let free_space = layout_size - tot_size;
if free_space <= 0.0 {
return;
}
let add_size = free_space / auto_tracks; let add_size = free_space / auto_tracks;
// Assign the space to the FRS // Assign the space to the FRS