mirror of
https://github.com/penpot/penpot.git
synced 2025-07-26 09:27:17 +02:00
✨ Improvements on flex layout positioning
This commit is contained in:
parent
4c12af957c
commit
a830c27ceb
6 changed files with 175 additions and 72 deletions
|
@ -116,8 +116,8 @@ struct ChildAxis {
|
|||
max_across_size: f32,
|
||||
is_fill_main: bool,
|
||||
is_fill_across: bool,
|
||||
is_absolute: bool,
|
||||
z_index: i32,
|
||||
bounds: Bounds,
|
||||
}
|
||||
|
||||
impl ChildAxis {
|
||||
|
@ -139,8 +139,8 @@ impl ChildAxis {
|
|||
max_across_size: layout_item.and_then(|i| i.max_h).unwrap_or(MAX_SIZE),
|
||||
is_fill_main: child.is_layout_horizontal_fill(),
|
||||
is_fill_across: child.is_layout_vertical_fill(),
|
||||
is_absolute: layout_item.map(|i| i.is_absolute).unwrap_or(false),
|
||||
z_index: layout_item.map(|i| i.z_index).unwrap_or(0),
|
||||
bounds: child_bounds.clone(),
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
|
@ -157,8 +157,8 @@ impl ChildAxis {
|
|||
max_main_size: layout_item.and_then(|i| i.max_h).unwrap_or(MAX_SIZE),
|
||||
is_fill_main: child.is_layout_vertical_fill(),
|
||||
is_fill_across: child.is_layout_horizontal_fill(),
|
||||
is_absolute: layout_item.map(|i| i.is_absolute).unwrap_or(false),
|
||||
z_index: layout_item.map(|i| i.z_index).unwrap_or(0),
|
||||
bounds: child_bounds.clone(),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -174,6 +174,7 @@ impl ChildAxis {
|
|||
|
||||
fn initialize_tracks(
|
||||
shape: &Shape,
|
||||
layout_bounds: &Bounds,
|
||||
layout_axis: &LayoutAxis,
|
||||
layout_data: &LayoutData,
|
||||
flex_data: &FlexData,
|
||||
|
@ -194,19 +195,32 @@ fn initialize_tracks(
|
|||
continue;
|
||||
};
|
||||
|
||||
let child_bounds = bounds.find(child);
|
||||
if child.is_absolute() || child.hidden() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let default_bounds = bounds.find(child);
|
||||
let child_bounds = layout_bounds
|
||||
.box_bounds(&default_bounds)
|
||||
.unwrap_or(default_bounds);
|
||||
|
||||
let child_axis = ChildAxis::new(child, &child_bounds, layout_data);
|
||||
|
||||
let child_main_size = if child_axis.is_fill_main {
|
||||
child_axis.min_main_size
|
||||
} else {
|
||||
child_axis.main_size
|
||||
};
|
||||
let child_across_size = if child_axis.is_fill_across {
|
||||
child_axis.min_across_size
|
||||
} else {
|
||||
child_axis.across_size
|
||||
};
|
||||
let child_main_size = child_axis.margin_main_start
|
||||
+ child_axis.margin_main_end
|
||||
+ if child_axis.is_fill_main {
|
||||
child_axis.min_main_size
|
||||
} else {
|
||||
child_axis.main_size
|
||||
};
|
||||
|
||||
let child_across_size = child_axis.margin_across_start
|
||||
+ child_axis.margin_across_end
|
||||
+ if child_axis.is_fill_across {
|
||||
child_axis.min_across_size
|
||||
} else {
|
||||
child_axis.across_size
|
||||
};
|
||||
|
||||
let child_max_across_size = if child_axis.is_fill_across {
|
||||
child_axis.max_across_size
|
||||
|
@ -271,6 +285,7 @@ fn distribute_fill_main_space(layout_axis: &LayoutAxis, tracks: &mut Vec<TrackDa
|
|||
f32::min(child.max_main_size, child.main_size + current) - child.main_size;
|
||||
child.main_size = child.main_size + delta;
|
||||
left_space = left_space - delta;
|
||||
track.main_size = track.main_size + delta;
|
||||
|
||||
if (child.main_size - child.max_main_size).abs() < MIN_SIZE {
|
||||
to_resize_children.remove(i);
|
||||
|
@ -315,9 +330,10 @@ fn distribute_fill_across_space(layout_axis: &LayoutAxis, tracks: &mut Vec<Track
|
|||
|
||||
for child in track.shapes.iter_mut() {
|
||||
if child.is_fill_across {
|
||||
child.across_size = track
|
||||
.across_size
|
||||
.clamp(child.min_across_size, child.max_across_size);
|
||||
let mut size =
|
||||
track.across_size - child.margin_across_start - child.margin_across_end;
|
||||
size = size.clamp(child.min_across_size, child.max_across_size);
|
||||
child.across_size = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +462,15 @@ fn calculate_track_data(
|
|||
bounds: &HashMap<Uuid, Bounds>,
|
||||
) -> Vec<TrackData> {
|
||||
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
|
||||
let mut tracks = initialize_tracks(shape, &layout_axis, layout_data, flex_data, shapes, bounds);
|
||||
let mut tracks = initialize_tracks(
|
||||
shape,
|
||||
layout_bounds,
|
||||
&layout_axis,
|
||||
layout_data,
|
||||
flex_data,
|
||||
shapes,
|
||||
bounds,
|
||||
);
|
||||
|
||||
if !layout_axis.is_auto_main {
|
||||
distribute_fill_main_space(&layout_axis, &mut tracks);
|
||||
|
@ -510,24 +534,26 @@ fn next_anchor(
|
|||
prev_anchor: Point,
|
||||
total_shapes_size: f32,
|
||||
) -> Point {
|
||||
let delta = match layout_data.justify_content {
|
||||
JustifyContent::SpaceBetween => {
|
||||
let effective_gap =
|
||||
(layout_axis.main_space() - total_shapes_size) / (track.shapes.len() - 1) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
JustifyContent::SpaceAround => {
|
||||
let effective_gap =
|
||||
(layout_axis.main_space() - total_shapes_size) / (track.shapes.len()) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
JustifyContent::SpaceEvenly => {
|
||||
let effective_gap =
|
||||
(layout_axis.main_space() - total_shapes_size) / (track.shapes.len() + 1) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
_ => child_axis.main_size + layout_axis.gap_main,
|
||||
};
|
||||
let delta = child_axis.margin_main_start
|
||||
+ child_axis.margin_main_end
|
||||
+ match layout_data.justify_content {
|
||||
JustifyContent::SpaceBetween => {
|
||||
let effective_gap = (layout_axis.main_space() - total_shapes_size)
|
||||
/ (track.shapes.len() - 1) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
JustifyContent::SpaceAround => {
|
||||
let effective_gap =
|
||||
(layout_axis.main_space() - total_shapes_size) / (track.shapes.len()) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
JustifyContent::SpaceEvenly => {
|
||||
let effective_gap = (layout_axis.main_space() - total_shapes_size)
|
||||
/ (track.shapes.len() + 1) as f32;
|
||||
child_axis.main_size + f32::max(layout_axis.gap_main, effective_gap)
|
||||
}
|
||||
_ => child_axis.main_size + layout_axis.gap_main,
|
||||
};
|
||||
prev_anchor + layout_axis.main_v * delta
|
||||
}
|
||||
|
||||
|
@ -539,22 +565,23 @@ fn child_position(
|
|||
child_axis: &ChildAxis,
|
||||
track: &TrackData,
|
||||
) -> Point {
|
||||
let delta = match child.layout_item {
|
||||
Some(LayoutItem {
|
||||
align_self: Some(align_self),
|
||||
..
|
||||
}) => match align_self {
|
||||
AlignSelf::Center => (track.across_size - child_axis.across_size) / 2.0,
|
||||
AlignSelf::End => track.across_size - child_axis.across_size,
|
||||
_ => 0.0,
|
||||
},
|
||||
_ => match layout_data.align_items {
|
||||
AlignItems::Center => (track.across_size - child_axis.across_size) / 2.0,
|
||||
AlignItems::End => track.across_size - child_axis.across_size,
|
||||
_ => 0.0,
|
||||
},
|
||||
};
|
||||
shape_anchor + layout_axis.across_v * delta
|
||||
let delta = child_axis.margin_across_start
|
||||
+ match child.layout_item {
|
||||
Some(LayoutItem {
|
||||
align_self: Some(align_self),
|
||||
..
|
||||
}) => match align_self {
|
||||
AlignSelf::Center => (track.across_size - child_axis.across_size) / 2.0,
|
||||
AlignSelf::End => track.across_size - child_axis.across_size,
|
||||
_ => 0.0,
|
||||
},
|
||||
_ => match layout_data.align_items {
|
||||
AlignItems::Center => (track.across_size - child_axis.across_size) / 2.0,
|
||||
AlignItems::End => track.across_size - child_axis.across_size,
|
||||
_ => 0.0,
|
||||
},
|
||||
};
|
||||
shape_anchor + layout_axis.main_v * child_axis.margin_main_start + layout_axis.across_v * delta
|
||||
}
|
||||
|
||||
pub fn reflow_flex_layout(
|
||||
|
@ -562,7 +589,7 @@ pub fn reflow_flex_layout(
|
|||
layout_data: &LayoutData,
|
||||
flex_data: &FlexData,
|
||||
shapes: &HashMap<Uuid, Shape>,
|
||||
bounds: &HashMap<Uuid, Bounds>,
|
||||
bounds: &mut HashMap<Uuid, Bounds>,
|
||||
) -> VecDeque<Modifier> {
|
||||
let mut result = VecDeque::new();
|
||||
let layout_bounds = &bounds.find(&shape);
|
||||
|
@ -587,7 +614,7 @@ pub fn reflow_flex_layout(
|
|||
child_axis,
|
||||
track,
|
||||
);
|
||||
let child_bounds = bounds.find(child);
|
||||
let child_bounds = &child_axis.bounds;
|
||||
let delta_v = Vector::new_points(&child_bounds.nw, &position);
|
||||
|
||||
let (new_width, new_height) = if layout_data.is_row() {
|
||||
|
@ -695,7 +722,9 @@ pub fn reflow_flex_layout(
|
|||
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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue