mirror of
https://github.com/penpot/penpot.git
synced 2025-07-13 14:17:16 +02:00
♻️ Refactor modifiers methods
This commit is contained in:
parent
afec3b9bc1
commit
36b6f6323a
1 changed files with 215 additions and 180 deletions
|
@ -150,44 +150,21 @@ fn set_pixel_precision(transform: &mut Matrix, bounds: &mut Bounds) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn propagate_modifiers(
|
fn propagate_transform(
|
||||||
state: &State,
|
entry: TransformEntry,
|
||||||
modifiers: &[TransformEntry],
|
|
||||||
pixel_precision: bool,
|
pixel_precision: bool,
|
||||||
) -> Vec<TransformEntry> {
|
state: &State,
|
||||||
let shapes = &state.shapes;
|
entries: &mut VecDeque<Modifier>,
|
||||||
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
let font_col = state.render_state.fonts.font_collection();
|
modifiers: &mut HashMap<Uuid, Matrix>,
|
||||||
let mut entries: VecDeque<_> = modifiers
|
) {
|
||||||
.iter()
|
|
||||||
.map(|entry| Modifier::Transform(entry.clone()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
for id in state.structure.keys() {
|
|
||||||
if id != &Uuid::nil() {
|
|
||||||
entries.push_back(Modifier::Reflow(*id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
|
||||||
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
|
||||||
|
|
||||||
let mut reflown = HashSet::<Uuid>::new();
|
|
||||||
let mut layout_reflows = Vec::<Uuid>::new();
|
|
||||||
|
|
||||||
// We first propagate the transforms to the children and then after
|
|
||||||
// recalculate the layouts. The layout can create further transforms that
|
|
||||||
// we need to re-propagate.
|
|
||||||
// In order for loop to eventualy finish, we limit the flex reflow to just
|
|
||||||
// one (the reflown set).
|
|
||||||
while !entries.is_empty() {
|
|
||||||
while let Some(modifier) = entries.pop_front() {
|
|
||||||
match modifier {
|
|
||||||
Modifier::Transform(entry) => {
|
|
||||||
let Some(shape) = state.shapes.get(&entry.id) else {
|
let Some(shape) = state.shapes.get(&entry.id) else {
|
||||||
continue;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
|
let font_col = state.render_state.fonts.font_collection();
|
||||||
|
|
||||||
let shape_bounds_before = bounds.find(shape);
|
let shape_bounds_before = bounds.find(shape);
|
||||||
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
|
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
|
||||||
|
|
||||||
|
@ -220,7 +197,7 @@ pub fn propagate_modifiers(
|
||||||
&shape_bounds_before,
|
&shape_bounds_before,
|
||||||
&shape_bounds_after,
|
&shape_bounds_after,
|
||||||
transform,
|
transform,
|
||||||
&bounds,
|
bounds,
|
||||||
&state.structure,
|
&state.structure,
|
||||||
&state.scale_content,
|
&state.scale_content,
|
||||||
);
|
);
|
||||||
|
@ -242,24 +219,30 @@ pub fn propagate_modifiers(
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
entries.push_back(Modifier::reflow(parent.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Modifier::Reflow(id) => {
|
fn propagate_reflow(
|
||||||
let Some(shape) = state.shapes.get(&id) else {
|
id: &Uuid,
|
||||||
continue;
|
state: &State,
|
||||||
|
entries: &mut VecDeque<Modifier>,
|
||||||
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
|
layout_reflows: &mut Vec<Uuid>,
|
||||||
|
reflown: &mut HashSet<Uuid>,
|
||||||
|
) {
|
||||||
|
let Some(shape) = state.shapes.get(id) else {
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
let mut reflow_parent = false;
|
let mut reflow_parent = false;
|
||||||
|
|
||||||
match &shape.shape_type {
|
match &shape.shape_type {
|
||||||
Type::Frame(Frame {
|
Type::Frame(Frame {
|
||||||
layout: Some(_), ..
|
layout: Some(_), ..
|
||||||
}) => {
|
}) => {
|
||||||
if !reflown.contains(&id) {
|
if !reflown.contains(id) {
|
||||||
let mut skip_reflow = false;
|
let mut skip_reflow = false;
|
||||||
if shape.is_layout_horizontal_fill()
|
if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() {
|
||||||
|| shape.is_layout_vertical_fill()
|
|
||||||
{
|
|
||||||
if let Some(parent_id) = shape.parent_id {
|
if let Some(parent_id) = shape.parent_id {
|
||||||
if !reflown.contains(&parent_id) {
|
if !reflown.contains(&parent_id) {
|
||||||
// If this is a fill layout but the parent has not been reflown yet
|
// If this is a fill layout but the parent has not been reflown yet
|
||||||
|
@ -270,20 +253,17 @@ pub fn propagate_modifiers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if shape.is_layout_vertical_auto()
|
if shape.is_layout_vertical_auto() || shape.is_layout_horizontal_auto() {
|
||||||
|| shape.is_layout_horizontal_auto()
|
|
||||||
{
|
|
||||||
reflow_parent = true;
|
reflow_parent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skip_reflow {
|
if !skip_reflow {
|
||||||
layout_reflows.push(id);
|
layout_reflows.push(*id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Group(Group { masked: true }) => {
|
Type::Group(Group { masked: true }) => {
|
||||||
let children_ids =
|
let children_ids = modified_children_ids(shape, state.structure.get(&shape.id), true);
|
||||||
modified_children_ids(shape, state.structure.get(&shape.id), true);
|
|
||||||
if let Some(child) = shapes.get(&children_ids[0]) {
|
if let Some(child) = shapes.get(&children_ids[0]) {
|
||||||
let child_bounds = bounds.find(child);
|
let child_bounds = bounds.find(child);
|
||||||
bounds.insert(shape.id, child_bounds);
|
bounds.insert(shape.id, child_bounds);
|
||||||
|
@ -292,7 +272,7 @@ pub fn propagate_modifiers(
|
||||||
}
|
}
|
||||||
Type::Group(_) => {
|
Type::Group(_) => {
|
||||||
if let Some(shape_bounds) =
|
if let Some(shape_bounds) =
|
||||||
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
|
calculate_group_bounds(shape, shapes, bounds, &state.structure)
|
||||||
{
|
{
|
||||||
bounds.insert(shape.id, shape_bounds);
|
bounds.insert(shape.id, shape_bounds);
|
||||||
reflow_parent = true;
|
reflow_parent = true;
|
||||||
|
@ -303,7 +283,7 @@ pub fn propagate_modifiers(
|
||||||
// new path... impossible right now. I'm going to use for the moment the group
|
// new path... impossible right now. I'm going to use for the moment the group
|
||||||
// calculation
|
// calculation
|
||||||
if let Some(shape_bounds) =
|
if let Some(shape_bounds) =
|
||||||
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
|
calculate_group_bounds(shape, shapes, bounds, &state.structure)
|
||||||
{
|
{
|
||||||
bounds.insert(shape.id, shape_bounds);
|
bounds.insert(shape.id, shape_bounds);
|
||||||
reflow_parent = true;
|
reflow_parent = true;
|
||||||
|
@ -319,19 +299,21 @@ pub fn propagate_modifiers(
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
entries.push_back(Modifier::reflow(parent.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for id in layout_reflows.iter() {
|
|
||||||
if reflown.contains(id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fn reflow_shape(
|
||||||
|
id: &Uuid,
|
||||||
|
state: &State,
|
||||||
|
reflown: &mut HashSet<Uuid>,
|
||||||
|
entries: &mut VecDeque<Modifier>,
|
||||||
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
|
) {
|
||||||
let Some(shape) = state.shapes.get(id) else {
|
let Some(shape) = state.shapes.get(id) else {
|
||||||
continue;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
|
|
||||||
let shape = if let Some(scale_content) = state.scale_content.get(id) {
|
let shape = if let Some(scale_content) = state.scale_content.get(id) {
|
||||||
&shape.scale_content(*scale_content)
|
&shape.scale_content(*scale_content)
|
||||||
} else {
|
} else {
|
||||||
|
@ -339,7 +321,7 @@ pub fn propagate_modifiers(
|
||||||
};
|
};
|
||||||
|
|
||||||
let Type::Frame(frame_data) = &shape.shape_type else {
|
let Type::Frame(frame_data) = &shape.shape_type else {
|
||||||
continue;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
|
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
|
||||||
|
@ -348,24 +330,77 @@ pub fn propagate_modifiers(
|
||||||
layout_data,
|
layout_data,
|
||||||
flex_data,
|
flex_data,
|
||||||
shapes,
|
shapes,
|
||||||
&mut bounds,
|
bounds,
|
||||||
&state.structure,
|
&state.structure,
|
||||||
);
|
);
|
||||||
entries.append(&mut children);
|
entries.append(&mut children);
|
||||||
}
|
} else 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 = grid_layout::reflow_grid_layout(
|
let mut children = grid_layout::reflow_grid_layout(
|
||||||
shape,
|
shape,
|
||||||
layout_data,
|
layout_data,
|
||||||
grid_data,
|
grid_data,
|
||||||
shapes,
|
shapes,
|
||||||
&mut bounds,
|
bounds,
|
||||||
&state.structure,
|
&state.structure,
|
||||||
);
|
);
|
||||||
entries.append(&mut children);
|
entries.append(&mut children);
|
||||||
}
|
}
|
||||||
reflown.insert(*id);
|
reflown.insert(*id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn propagate_modifiers(
|
||||||
|
state: &State,
|
||||||
|
modifiers: &[TransformEntry],
|
||||||
|
pixel_precision: bool,
|
||||||
|
) -> Vec<TransformEntry> {
|
||||||
|
let mut entries: VecDeque<_> = modifiers
|
||||||
|
.iter()
|
||||||
|
.map(|entry| Modifier::Transform(entry.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for id in state.structure.keys() {
|
||||||
|
if id != &Uuid::nil() {
|
||||||
|
entries.push_back(Modifier::Reflow(*id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
||||||
|
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
||||||
|
let mut reflown = HashSet::<Uuid>::new();
|
||||||
|
let mut layout_reflows = Vec::<Uuid>::new();
|
||||||
|
|
||||||
|
// We first propagate the transforms to the children and then after
|
||||||
|
// recalculate the layouts. The layout can create further transforms that
|
||||||
|
// we need to re-propagate.
|
||||||
|
// In order for loop to eventualy finish, we limit the flex reflow to just
|
||||||
|
// one (the reflown set).
|
||||||
|
while !entries.is_empty() {
|
||||||
|
while let Some(modifier) = entries.pop_front() {
|
||||||
|
match modifier {
|
||||||
|
Modifier::Transform(entry) => propagate_transform(
|
||||||
|
entry,
|
||||||
|
pixel_precision,
|
||||||
|
state,
|
||||||
|
&mut entries,
|
||||||
|
&mut bounds,
|
||||||
|
&mut modifiers,
|
||||||
|
),
|
||||||
|
Modifier::Reflow(id) => propagate_reflow(
|
||||||
|
&id,
|
||||||
|
state,
|
||||||
|
&mut entries,
|
||||||
|
&mut bounds,
|
||||||
|
&mut layout_reflows,
|
||||||
|
&mut reflown,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in layout_reflows.iter() {
|
||||||
|
if reflown.contains(id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds);
|
||||||
}
|
}
|
||||||
layout_reflows = Vec::new();
|
layout_reflows = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue