mirror of
https://github.com/penpot/penpot.git
synced 2025-04-29 17:06:21 +02:00
Merge pull request #6274 from penpot/alotor-perf-grid-layout-modifiers-3
✨ Modifiers grid multi-span
This commit is contained in:
commit
99e64ad387
4 changed files with 373 additions and 203 deletions
|
@ -357,7 +357,8 @@
|
||||||
to-idx (+ (dec (get cell prop)) (get cell prop-span))
|
to-idx (+ (dec (get cell prop)) (get cell prop-span))
|
||||||
indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx)
|
indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx)
|
||||||
|
|
||||||
to-allocate (size-to-allocate type parent (get children-map shape-id) cell bounds objects)
|
to-allocate
|
||||||
|
(size-to-allocate type parent (get children-map shape-id) cell bounds objects)
|
||||||
|
|
||||||
;; Remove the size and the tracks that are not allocated
|
;; Remove the size and the tracks that are not allocated
|
||||||
[to-allocate total-frs indexed-tracks]
|
[to-allocate total-frs indexed-tracks]
|
||||||
|
|
|
@ -255,8 +255,13 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
|
if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
|
||||||
let mut children =
|
let mut children = grid_layout::reflow_grid_layout(
|
||||||
grid_layout::reflow_grid_layout(shape, layout_data, grid_data, shapes, &bounds);
|
shape,
|
||||||
|
layout_data,
|
||||||
|
grid_data,
|
||||||
|
shapes,
|
||||||
|
&mut bounds,
|
||||||
|
);
|
||||||
entries.append(&mut children);
|
entries.append(&mut children);
|
||||||
}
|
}
|
||||||
reflown.insert(*id);
|
reflown.insert(*id);
|
||||||
|
|
|
@ -412,94 +412,6 @@ fn calculate_track_positions(
|
||||||
track.anchor = next_anchor;
|
track.anchor = next_anchor;
|
||||||
next_anchor = next_anchor + layout_axis.across_v * real_gap;
|
next_anchor = next_anchor + layout_axis.across_v * real_gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
match align_content {
|
|
||||||
AlignContent::End => {
|
|
||||||
let total_across_size_gap: f32 =
|
|
||||||
total_across_size + (tracks.len() - 1) as f32 * layout_axis.gap_across;
|
|
||||||
|
|
||||||
let delta =
|
|
||||||
layout_axis.across_size - total_across_size_gap - layout_axis.padding_across_end;
|
|
||||||
let mut next_anchor = layout_bounds.nw + layout_axis.across_v * delta;
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor = next_anchor
|
|
||||||
+ layout_axis.across_v * (track.across_size + layout_axis.gap_across);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignContent::Center => {
|
|
||||||
let total_across_size_gap: f32 =
|
|
||||||
total_across_size + (tracks.len() - 1) as f32 * layout_axis.gap_across;
|
|
||||||
let center_margin = (layout_axis.across_size - total_across_size_gap) / 2.0;
|
|
||||||
|
|
||||||
let mut next_anchor = layout_bounds.nw + layout_axis.across_v * center_margin;
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor = next_anchor
|
|
||||||
+ layout_axis.across_v * (track.across_size + layout_axis.gap_across);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignContent::SpaceBetween => {
|
|
||||||
let mut next_anchor =
|
|
||||||
layout_bounds.nw + layout_axis.across_v * layout_axis.padding_across_start;
|
|
||||||
|
|
||||||
let effective_gap = f32::max(
|
|
||||||
layout_axis.gap_across,
|
|
||||||
(layout_axis.across_space() - total_across_size) / (tracks.len() - 1) as f32,
|
|
||||||
);
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor =
|
|
||||||
next_anchor + layout_axis.across_v * (track.across_size + effective_gap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignContent::SpaceAround => {
|
|
||||||
let effective_gap =
|
|
||||||
(layout_axis.across_space() - total_across_size) / tracks.len() as f32;
|
|
||||||
|
|
||||||
let mut next_anchor = layout_bounds.nw
|
|
||||||
+ layout_axis.across_v * (layout_axis.padding_across_start + effective_gap / 2.0);
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor =
|
|
||||||
next_anchor + layout_axis.across_v * (track.across_size + effective_gap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlignContent::SpaceEvenly => {
|
|
||||||
let effective_gap =
|
|
||||||
(layout_axis.across_space() - total_across_size) / (tracks.len() + 1) as f32;
|
|
||||||
|
|
||||||
let mut next_anchor = layout_bounds.nw
|
|
||||||
+ layout_axis.across_v * (layout_axis.padding_across_start + effective_gap);
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor =
|
|
||||||
next_anchor + layout_axis.across_v * (track.across_size + effective_gap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
let mut next_anchor =
|
|
||||||
layout_bounds.nw + layout_axis.across_v * layout_axis.padding_across_start;
|
|
||||||
|
|
||||||
for track in tracks.iter_mut() {
|
|
||||||
track.anchor = next_anchor;
|
|
||||||
next_anchor = next_anchor
|
|
||||||
+ layout_axis.across_v * (track.across_size + layout_axis.gap_across);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_track_data(
|
fn calculate_track_data(
|
||||||
|
@ -708,8 +620,8 @@ pub fn reflow_flex_layout(
|
||||||
let auto_across_size = if layout_axis.is_auto_across {
|
let auto_across_size = if layout_axis.is_auto_across {
|
||||||
tracks.iter().map(|track| track.across_size).sum::<f32>()
|
tracks.iter().map(|track| track.across_size).sum::<f32>()
|
||||||
+ (tracks.len() - 1) as f32 * layout_axis.gap_across
|
+ (tracks.len() - 1) as f32 * layout_axis.gap_across
|
||||||
+ layout_axis.padding_main_start
|
+ layout_axis.padding_across_start
|
||||||
+ layout_axis.padding_main_end
|
+ layout_axis.padding_across_end
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
@ -723,8 +635,8 @@ pub fn reflow_flex_layout(
|
||||||
})
|
})
|
||||||
.reduce(f32::max)
|
.reduce(f32::max)
|
||||||
.unwrap_or(0.01)
|
.unwrap_or(0.01)
|
||||||
+ layout_axis.padding_across_start
|
+ layout_axis.padding_main_start
|
||||||
+ layout_axis.padding_across_end
|
+ layout_axis.padding_main_end
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#![allow(dead_code, unused_variables)]
|
use crate::math::{self as math, intersect_rays, Bounds, Matrix, Point, Ray, Vector, VectorExt};
|
||||||
use crate::math::{intersect_rays, Bounds, Matrix, Point, Ray, Vector, VectorExt};
|
|
||||||
use crate::shapes::{
|
use crate::shapes::{
|
||||||
AlignContent, AlignItems, AlignSelf, GridCell, GridData, GridTrack, GridTrackType,
|
AlignContent, AlignItems, AlignSelf, GridCell, GridData, GridTrack, GridTrackType,
|
||||||
JustifyContent, JustifyItems, JustifySelf, LayoutData, LayoutItem, Modifier, Shape,
|
JustifyContent, JustifyItems, JustifySelf, LayoutData, LayoutItem, Modifier, Shape,
|
||||||
|
@ -34,6 +33,7 @@ struct TrackData {
|
||||||
|
|
||||||
fn calculate_tracks(
|
fn calculate_tracks(
|
||||||
is_column: bool,
|
is_column: bool,
|
||||||
|
shape: &Shape,
|
||||||
layout_data: &LayoutData,
|
layout_data: &LayoutData,
|
||||||
grid_data: &GridData,
|
grid_data: &GridData,
|
||||||
layout_bounds: &Bounds,
|
layout_bounds: &Bounds,
|
||||||
|
@ -55,14 +55,11 @@ 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, layout_data, &layout_bounds, &mut tracks);
|
set_flex_multi_span(is_column, &mut tracks, cells, shapes, bounds);
|
||||||
set_flex_multi_span(is_column, layout_data, &layout_bounds, &mut tracks);
|
set_fr_value(is_column, shape, layout_data, &mut tracks, layout_size);
|
||||||
|
stretch_tracks(is_column, shape, layout_data, &mut tracks, layout_size);
|
||||||
set_fr_value(is_column, layout_data, &mut tracks, layout_size, 0.0);
|
|
||||||
stretch_tracks(is_column, 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);
|
||||||
|
|
||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +84,20 @@ fn init_tracks(track: &Vec<GridTrack>, size: f32) -> Vec<TrackData> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn min_size(column: bool, shape: &Shape, bounds: &HashMap<Uuid, Bounds>) -> f32 {
|
||||||
|
if column && shape.is_layout_horizontal_fill() {
|
||||||
|
shape.layout_item.and_then(|i| i.min_w).unwrap_or(MIN_SIZE)
|
||||||
|
} else if !column && shape.is_layout_vertical_fill() {
|
||||||
|
shape.layout_item.and_then(|i| i.min_h).unwrap_or(MIN_SIZE)
|
||||||
|
} else if column {
|
||||||
|
let bounds = bounds.find(shape);
|
||||||
|
bounds.width()
|
||||||
|
} else {
|
||||||
|
let bounds = bounds.find(shape);
|
||||||
|
bounds.height()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Go through cells to adjust auto sizes for span=1. Base is the max of its children
|
// Go through cells to adjust auto sizes for span=1. Base is the max of its children
|
||||||
fn set_auto_base_size(
|
fn set_auto_base_size(
|
||||||
column: bool,
|
column: bool,
|
||||||
|
@ -108,6 +119,7 @@ fn set_auto_base_size(
|
||||||
|
|
||||||
let track = &mut tracks[(prop - 1) as usize];
|
let track = &mut tracks[(prop - 1) as usize];
|
||||||
|
|
||||||
|
// We change the size for auto+flex tracks
|
||||||
if track.track_type != GridTrackType::Auto && track.track_type != GridTrackType::Flex {
|
if track.track_type != GridTrackType::Auto && track.track_type != GridTrackType::Flex {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -116,62 +128,208 @@ fn set_auto_base_size(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let bounds = bounds.find(shape);
|
let min_size = min_size(column, shape, bounds);
|
||||||
|
|
||||||
let shape_size = if column {
|
|
||||||
bounds.width()
|
|
||||||
} else {
|
|
||||||
bounds.height()
|
|
||||||
};
|
|
||||||
|
|
||||||
let min_size = if column && shape.is_layout_horizontal_fill() {
|
|
||||||
shape.layout_item.and_then(|i| i.min_w).unwrap_or(MIN_SIZE)
|
|
||||||
} else if !column && shape.is_layout_vertical_fill() {
|
|
||||||
shape.layout_item.and_then(|i| i.min_h).unwrap_or(MIN_SIZE)
|
|
||||||
} else {
|
|
||||||
shape_size
|
|
||||||
};
|
|
||||||
|
|
||||||
track.size = f32::max(track.size, min_size);
|
track.size = f32::max(track.size, min_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn track_index(is_column: bool, c: &GridCell) -> (usize, usize) {
|
||||||
|
if is_column {
|
||||||
|
(
|
||||||
|
(c.column - 1) as usize,
|
||||||
|
(c.column + c.column_span - 1) as usize,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
((c.row - 1) as usize, (c.row + c.row_span - 1) as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_flex(is_column: bool, cell: &GridCell, tracks: &mut Vec<TrackData>) -> bool {
|
||||||
|
let (start, end) = track_index(is_column, cell);
|
||||||
|
(start..end).any(|i| tracks[i].track_type == GridTrackType::Flex)
|
||||||
|
}
|
||||||
|
|
||||||
// Adjust multi-spaned cells with no flex columns
|
// Adjust multi-spaned cells with no flex columns
|
||||||
fn set_auto_multi_span(
|
fn set_auto_multi_span(
|
||||||
_column: bool,
|
column: bool,
|
||||||
_layout_data: &LayoutData,
|
tracks: &mut Vec<TrackData>,
|
||||||
_layout_bounds: &Bounds,
|
cells: &Vec<GridCell>,
|
||||||
_tracks: &mut Vec<TrackData>,
|
shapes: &HashMap<Uuid, Shape>,
|
||||||
|
bounds: &HashMap<Uuid, Bounds>,
|
||||||
) {
|
) {
|
||||||
// Sort descendant order of prop-span
|
|
||||||
// Remove groups with flex (will be set in flex_multi_span)
|
// Remove groups with flex (will be set in flex_multi_span)
|
||||||
// Retrieve teh value we need to distribute (fixed cell size minus gaps)
|
let mut selected_cells: Vec<&GridCell> = cells
|
||||||
// Distribute the size between the tracks that already have a set value
|
.iter()
|
||||||
// Distribute the space between auto tracks
|
.filter(|c| {
|
||||||
// If we still have more space we distribute equally between all tracks
|
if column {
|
||||||
|
c.column_span > 1
|
||||||
|
} else {
|
||||||
|
c.row_span > 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(|c| !has_flex(column, c, tracks))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Sort descendant order of prop-span
|
||||||
|
selected_cells.sort_by(|a, b| {
|
||||||
|
if column {
|
||||||
|
b.column_span.cmp(&a.row_span)
|
||||||
|
} else {
|
||||||
|
b.row_span.cmp(&a.row_span)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for cell in selected_cells {
|
||||||
|
let Some(child) = cell.shape.and_then(|id| shapes.get(&id)) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve the value we need to distribute (fixed cell size minus gaps)
|
||||||
|
let mut dist = min_size(column, child, bounds);
|
||||||
|
let mut num_auto = 0;
|
||||||
|
|
||||||
|
let (start, end) = track_index(column, cell);
|
||||||
|
|
||||||
|
// Distribute the size between the tracks that already have a set value
|
||||||
|
for i in start..end {
|
||||||
|
dist = dist - tracks[i].size;
|
||||||
|
|
||||||
|
if tracks[i].track_type == GridTrackType::Auto {
|
||||||
|
num_auto = num_auto + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we still have more space we distribute equally between all auto tracks
|
||||||
|
while dist > MIN_SIZE && num_auto > 0 {
|
||||||
|
let rest = dist / num_auto as f32;
|
||||||
|
|
||||||
|
// Distribute the space between auto tracks
|
||||||
|
for i in start..end {
|
||||||
|
if tracks[i].track_type == GridTrackType::Auto {
|
||||||
|
// dist = dist - track[i].size;
|
||||||
|
let new_size = if tracks[i].size + rest < tracks[i].max_size {
|
||||||
|
tracks[i].size + rest
|
||||||
|
} else {
|
||||||
|
num_auto = num_auto - 1;
|
||||||
|
tracks[i].max_size
|
||||||
|
};
|
||||||
|
|
||||||
|
let aloc = new_size - tracks[i].size;
|
||||||
|
dist = dist - aloc;
|
||||||
|
tracks[i].size = tracks[i].size + aloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 Vec<TrackData>,
|
||||||
_layout_bounds: &Bounds,
|
cells: &Vec<GridCell>,
|
||||||
_tracks: &mut Vec<TrackData>,
|
shapes: &HashMap<Uuid, Shape>,
|
||||||
|
bounds: &HashMap<Uuid, Bounds>,
|
||||||
) {
|
) {
|
||||||
|
// Remove groups without flex
|
||||||
|
let mut selected_cells: Vec<&GridCell> = cells
|
||||||
|
.iter()
|
||||||
|
.filter(|c| {
|
||||||
|
if column {
|
||||||
|
c.column_span > 1
|
||||||
|
} else {
|
||||||
|
c.row_span > 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(|c| has_flex(column, c, tracks))
|
||||||
|
.collect();
|
||||||
|
|
||||||
// Sort descendant order of prop-span
|
// Sort descendant order of prop-span
|
||||||
// Remove groups without flex (will be set in flex_auto_span)
|
selected_cells.sort_by(|a, b| {
|
||||||
// Retrieve the value that we need to distribute (fixed size of cell minus gaps)
|
if column {
|
||||||
// Distribute the size first between the tracks that have the fixed size
|
b.column_span.cmp(&a.row_span)
|
||||||
// When finished we distribute equally between the the rest of the tracks
|
} else {
|
||||||
|
b.row_span.cmp(&a.row_span)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve the value that we need to distribute and the number of frs
|
||||||
|
for cell in selected_cells {
|
||||||
|
let Some(child) = cell.shape.and_then(|id| shapes.get(&id)) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Distribute the size between the tracks that already have a set value
|
||||||
|
for i in start..end {
|
||||||
|
dist = dist - tracks[i].size;
|
||||||
|
|
||||||
|
match tracks[i].track_type {
|
||||||
|
GridTrackType::Flex => {
|
||||||
|
num_flex = num_flex + tracks[i].value;
|
||||||
|
num_auto = num_auto + 1;
|
||||||
|
}
|
||||||
|
GridTrackType::Auto => {
|
||||||
|
num_auto = num_auto + 1;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if dist <= MIN_SIZE {
|
||||||
|
// No space available to distribute
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rest = dist / num_flex as f32;
|
||||||
|
|
||||||
|
// Distribute the space between flex tracks in proportion to the division
|
||||||
|
for i in start..end {
|
||||||
|
if tracks[i].track_type == GridTrackType::Flex {
|
||||||
|
let new_size = f32::min(tracks[i].size + rest, tracks[i].max_size);
|
||||||
|
let aloc = new_size - tracks[i].size;
|
||||||
|
dist = dist - aloc;
|
||||||
|
tracks[i].size = tracks[i].size + aloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribute the space between auto tracks if any
|
||||||
|
while dist > MIN_SIZE && num_auto > 0 {
|
||||||
|
let rest = dist / num_auto as f32;
|
||||||
|
|
||||||
|
for i in start..end {
|
||||||
|
if tracks[i].track_type == GridTrackType::Auto
|
||||||
|
|| tracks[i].track_type == GridTrackType::Flex
|
||||||
|
{
|
||||||
|
let new_size = if tracks[i].size + rest < tracks[i].max_size {
|
||||||
|
tracks[i].size + rest
|
||||||
|
} else {
|
||||||
|
num_auto = num_auto - 1;
|
||||||
|
tracks[i].max_size
|
||||||
|
};
|
||||||
|
|
||||||
|
let aloc = new_size - tracks[i].size;
|
||||||
|
dist = dist - aloc;
|
||||||
|
tracks[i].size = tracks[i].size + aloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 Vec<TrackData>,
|
tracks: &mut Vec<TrackData>,
|
||||||
layout_size: f32,
|
layout_size: f32,
|
||||||
min_fr_size: f32,
|
|
||||||
) {
|
) {
|
||||||
let tot_gap: f32 = if column {
|
let tot_gap: f32 = if column {
|
||||||
layout_data.column_gap * (tracks.len() - 1) as f32
|
layout_data.column_gap * (tracks.len() - 1) as f32
|
||||||
|
@ -187,31 +345,48 @@ fn set_fr_value(
|
||||||
.sum::<f32>()
|
.sum::<f32>()
|
||||||
+ tot_gap;
|
+ tot_gap;
|
||||||
|
|
||||||
// Get the total of frs to divide the space into
|
|
||||||
let tot_frs: f32 = tracks
|
let tot_frs: f32 = tracks
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|t| t.track_type == GridTrackType::Flex)
|
.filter(|t| t.track_type == GridTrackType::Flex)
|
||||||
.map(|t| t.value)
|
.map(|t| t.value)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
|
let cur_fr_size = tracks
|
||||||
|
.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
|
// Divide the space between FRS
|
||||||
let fr = f32::max(min_fr_size, (layout_size - tot_size) / tot_frs);
|
let fr = if column && shape.is_layout_horizontal_auto()
|
||||||
|
|| !column && shape.is_layout_vertical_auto()
|
||||||
|
{
|
||||||
|
cur_fr_size
|
||||||
|
} else {
|
||||||
|
f32::max(cur_fr_size, (layout_size - tot_size) / tot_frs)
|
||||||
|
};
|
||||||
|
|
||||||
// Assign the space to the FRS
|
// Assign the space to the FRS
|
||||||
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::max(t.size, fr * t.value));
|
.for_each(|t| t.size = f32::min(fr * t.value, t.max_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stretch_tracks(
|
fn stretch_tracks(
|
||||||
column: bool,
|
column: bool,
|
||||||
|
shape: &Shape,
|
||||||
layout_data: &LayoutData,
|
layout_data: &LayoutData,
|
||||||
tracks: &mut Vec<TrackData>,
|
tracks: &mut Vec<TrackData>,
|
||||||
layout_size: f32,
|
layout_size: f32,
|
||||||
) {
|
) {
|
||||||
if (column && layout_data.justify_content != JustifyContent::Stretch)
|
if (column
|
||||||
|| (!column && layout_data.align_content != AlignContent::Stretch)
|
&& (layout_data.justify_content != JustifyContent::Stretch
|
||||||
|
|| shape.is_layout_horizontal_auto()))
|
||||||
|
|| (!column
|
||||||
|
&& (layout_data.align_content != AlignContent::Stretch
|
||||||
|
|| shape.is_layout_vertical_auto()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -373,46 +548,8 @@ fn create_cell_data<'a>(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_cell_data<'a>(
|
|
||||||
shape: &Shape,
|
|
||||||
layout_data: &LayoutData,
|
|
||||||
grid_data: &GridData,
|
|
||||||
shapes: &'a HashMap<Uuid, Shape>,
|
|
||||||
bounds: &HashMap<Uuid, Bounds>,
|
|
||||||
) -> Vec<CellData<'a>> {
|
|
||||||
let result: Vec<CellData<'a>> = vec![];
|
|
||||||
|
|
||||||
let layout_bounds = bounds.find(shape);
|
|
||||||
|
|
||||||
let column_tracks = calculate_tracks(
|
|
||||||
true,
|
|
||||||
layout_data,
|
|
||||||
grid_data,
|
|
||||||
&layout_bounds,
|
|
||||||
&grid_data.cells,
|
|
||||||
shapes,
|
|
||||||
bounds,
|
|
||||||
);
|
|
||||||
let row_tracks = calculate_tracks(
|
|
||||||
false,
|
|
||||||
layout_data,
|
|
||||||
grid_data,
|
|
||||||
&layout_bounds,
|
|
||||||
&grid_data.cells,
|
|
||||||
shapes,
|
|
||||||
bounds,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_cell_data(
|
|
||||||
&layout_bounds,
|
|
||||||
shapes,
|
|
||||||
&grid_data.cells,
|
|
||||||
&column_tracks,
|
|
||||||
&row_tracks,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn child_position(
|
fn child_position(
|
||||||
|
child: &Shape,
|
||||||
layout_bounds: &Bounds,
|
layout_bounds: &Bounds,
|
||||||
layout_data: &LayoutData,
|
layout_data: &LayoutData,
|
||||||
child_bounds: &Bounds,
|
child_bounds: &Bounds,
|
||||||
|
@ -427,23 +564,37 @@ fn child_position(
|
||||||
let margin_right = layout_item.map(|i| i.margin_right).unwrap_or(0.0);
|
let margin_right = layout_item.map(|i| i.margin_right).unwrap_or(0.0);
|
||||||
let margin_bottom = layout_item.map(|i| i.margin_bottom).unwrap_or(0.0);
|
let margin_bottom = layout_item.map(|i| i.margin_bottom).unwrap_or(0.0);
|
||||||
|
|
||||||
cell.anchor
|
let vpos = match (cell.align_self, layout_data.align_items) {
|
||||||
+ vv * match (cell.align_self, layout_data.align_items) {
|
(Some(AlignSelf::Start), _) => margin_top,
|
||||||
(Some(AlignSelf::Start), _) => margin_left,
|
(Some(AlignSelf::Center), _) => (cell.height - child_bounds.height()) / 2.0,
|
||||||
(Some(AlignSelf::Center), _) => (cell.height - child_bounds.height()) / 2.0,
|
(Some(AlignSelf::End), _) => margin_bottom + cell.height - child_bounds.height(),
|
||||||
(Some(AlignSelf::End), _) => margin_right + cell.height - child_bounds.height(),
|
(_, AlignItems::Center) => (cell.height - child_bounds.height()) / 2.0,
|
||||||
(_, AlignItems::Center) => (cell.height - child_bounds.height()) / 2.0,
|
(_, AlignItems::End) => margin_bottom + cell.height - child_bounds.height(),
|
||||||
(_, AlignItems::End) => margin_right + cell.height - child_bounds.height(),
|
_ => margin_top,
|
||||||
_ => margin_left,
|
};
|
||||||
}
|
|
||||||
+ hv * match (cell.justify_self, layout_data.justify_items) {
|
let vpos = if child.is_layout_vertical_fill() {
|
||||||
(Some(JustifySelf::Start), _) => margin_top,
|
margin_top
|
||||||
(Some(JustifySelf::Center), _) => (cell.width - child_bounds.width()) / 2.0,
|
} else {
|
||||||
(Some(JustifySelf::End), _) => margin_bottom + cell.width - child_bounds.width(),
|
vpos
|
||||||
(_, JustifyItems::Center) => (cell.width - child_bounds.width()) / 2.0,
|
};
|
||||||
(_, JustifyItems::End) => margin_bottom + cell.width - child_bounds.width(),
|
|
||||||
_ => margin_top,
|
let hpos = match (cell.justify_self, layout_data.justify_items) {
|
||||||
}
|
(Some(JustifySelf::Start), _) => margin_left,
|
||||||
|
(Some(JustifySelf::Center), _) => (cell.width - child_bounds.width()) / 2.0,
|
||||||
|
(Some(JustifySelf::End), _) => margin_right + cell.width - child_bounds.width(),
|
||||||
|
(_, JustifyItems::Center) => (cell.width - child_bounds.width()) / 2.0,
|
||||||
|
(_, JustifyItems::End) => margin_right + cell.width - child_bounds.width(),
|
||||||
|
_ => margin_left,
|
||||||
|
};
|
||||||
|
|
||||||
|
let hpos = if child.is_layout_horizontal_fill() {
|
||||||
|
margin_left
|
||||||
|
} else {
|
||||||
|
hpos
|
||||||
|
};
|
||||||
|
|
||||||
|
cell.anchor + vv * vpos + hv * hpos
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reflow_grid_layout<'a>(
|
pub fn reflow_grid_layout<'a>(
|
||||||
|
@ -451,17 +602,78 @@ pub fn reflow_grid_layout<'a>(
|
||||||
layout_data: &LayoutData,
|
layout_data: &LayoutData,
|
||||||
grid_data: &GridData,
|
grid_data: &GridData,
|
||||||
shapes: &'a HashMap<Uuid, Shape>,
|
shapes: &'a HashMap<Uuid, Shape>,
|
||||||
bounds: &HashMap<Uuid, Bounds>,
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
) -> VecDeque<Modifier> {
|
) -> VecDeque<Modifier> {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
|
|
||||||
let cells = calculate_cell_data(shape, layout_data, grid_data, shapes, bounds);
|
|
||||||
let layout_bounds = bounds.find(shape);
|
let layout_bounds = bounds.find(shape);
|
||||||
|
|
||||||
|
let column_tracks = calculate_tracks(
|
||||||
|
true,
|
||||||
|
shape,
|
||||||
|
layout_data,
|
||||||
|
grid_data,
|
||||||
|
&layout_bounds,
|
||||||
|
&grid_data.cells,
|
||||||
|
shapes,
|
||||||
|
bounds,
|
||||||
|
);
|
||||||
|
|
||||||
|
let row_tracks = calculate_tracks(
|
||||||
|
false,
|
||||||
|
shape,
|
||||||
|
layout_data,
|
||||||
|
grid_data,
|
||||||
|
&layout_bounds,
|
||||||
|
&grid_data.cells,
|
||||||
|
shapes,
|
||||||
|
bounds,
|
||||||
|
);
|
||||||
|
|
||||||
|
let cells = create_cell_data(
|
||||||
|
&layout_bounds,
|
||||||
|
shapes,
|
||||||
|
&grid_data.cells,
|
||||||
|
&column_tracks,
|
||||||
|
&row_tracks,
|
||||||
|
);
|
||||||
|
|
||||||
for cell in cells.iter() {
|
for cell in cells.iter() {
|
||||||
let child = cell.shape;
|
let child = cell.shape;
|
||||||
let child_bounds = bounds.find(child);
|
let child_bounds = bounds.find(child);
|
||||||
|
|
||||||
|
let mut new_width = child_bounds.width();
|
||||||
|
if child.is_layout_horizontal_fill() {
|
||||||
|
let margin_left = child.layout_item.map(|i| i.margin_left).unwrap_or(0.0);
|
||||||
|
new_width = cell.width - margin_left;
|
||||||
|
let min_width = child.layout_item.and_then(|i| i.min_w).unwrap_or(MIN_SIZE);
|
||||||
|
let max_width = child.layout_item.and_then(|i| i.max_w).unwrap_or(MAX_SIZE);
|
||||||
|
new_width = new_width.clamp(min_width, max_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_height = child_bounds.height();
|
||||||
|
if child.is_layout_vertical_fill() {
|
||||||
|
let margin_top = child.layout_item.map(|i| i.margin_top).unwrap_or(0.0);
|
||||||
|
new_height = cell.height - margin_top;
|
||||||
|
let min_height = child.layout_item.and_then(|i| i.min_h).unwrap_or(MIN_SIZE);
|
||||||
|
let max_height = child.layout_item.and_then(|i| i.max_h).unwrap_or(MAX_SIZE);
|
||||||
|
new_height = new_height.clamp(min_height, max_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut transform = Matrix::default();
|
||||||
|
|
||||||
|
if (new_width - child_bounds.width()).abs() > MIN_SIZE
|
||||||
|
|| (new_height - child_bounds.height()).abs() > MIN_SIZE
|
||||||
|
{
|
||||||
|
transform.post_concat(&math::resize_matrix(
|
||||||
|
&layout_bounds,
|
||||||
|
&child_bounds,
|
||||||
|
new_width,
|
||||||
|
new_height,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let position = child_position(
|
let position = child_position(
|
||||||
|
&child,
|
||||||
&layout_bounds,
|
&layout_bounds,
|
||||||
&layout_data,
|
&layout_data,
|
||||||
&child_bounds,
|
&child_bounds,
|
||||||
|
@ -469,7 +681,6 @@ pub fn reflow_grid_layout<'a>(
|
||||||
cell,
|
cell,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut transform = Matrix::default();
|
|
||||||
let delta_v = Vector::new_points(&child_bounds.nw, &position);
|
let delta_v = Vector::new_points(&child_bounds.nw, &position);
|
||||||
|
|
||||||
if delta_v.x.abs() > MIN_SIZE || delta_v.y.abs() > MIN_SIZE {
|
if delta_v.x.abs() > MIN_SIZE || delta_v.y.abs() > MIN_SIZE {
|
||||||
|
@ -479,5 +690,46 @@ pub fn reflow_grid_layout<'a>(
|
||||||
result.push_back(Modifier::transform(child.id, transform));
|
result.push_back(Modifier::transform(child.id, transform));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shape.is_layout_horizontal_auto() || shape.is_layout_vertical_auto() {
|
||||||
|
let width = layout_bounds.width();
|
||||||
|
let height = layout_bounds.height();
|
||||||
|
|
||||||
|
let mut scale_width = 1.0;
|
||||||
|
let mut scale_height = 1.0;
|
||||||
|
|
||||||
|
if shape.is_layout_horizontal_auto() {
|
||||||
|
let auto_width = column_tracks.iter().map(|t| t.size).sum::<f32>()
|
||||||
|
+ layout_data.padding_left
|
||||||
|
+ layout_data.padding_right
|
||||||
|
+ (column_tracks.len() - 1) as f32 * layout_data.column_gap;
|
||||||
|
scale_width = auto_width / width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if shape.is_layout_vertical_auto() {
|
||||||
|
let auto_height = row_tracks.iter().map(|t| t.size).sum::<f32>()
|
||||||
|
+ layout_data.padding_top
|
||||||
|
+ layout_data.padding_bottom
|
||||||
|
+ (row_tracks.len() - 1) as f32 * layout_data.row_gap;
|
||||||
|
scale_height = auto_height / height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parent_transform = layout_bounds
|
||||||
|
.transform_matrix()
|
||||||
|
.unwrap_or(Matrix::default());
|
||||||
|
|
||||||
|
let parent_transform_inv = &parent_transform.invert().unwrap();
|
||||||
|
let origin = parent_transform_inv.map_point(layout_bounds.nw);
|
||||||
|
|
||||||
|
let mut scale = Matrix::scale((scale_width, scale_height));
|
||||||
|
scale.post_translate(origin);
|
||||||
|
scale.post_concat(&parent_transform);
|
||||||
|
scale.pre_translate(-origin);
|
||||||
|
scale.pre_concat(&parent_transform_inv);
|
||||||
|
|
||||||
|
let layout_bounds_after = layout_bounds.transform(&scale);
|
||||||
|
result.push_back(Modifier::parent(shape.id, scale));
|
||||||
|
bounds.insert(shape.id, layout_bounds_after);
|
||||||
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue