mirror of
https://github.com/penpot/penpot.git
synced 2025-07-13 11:07:18 +02:00
♻️ Refactor modifiers methods
This commit is contained in:
parent
afec3b9bc1
commit
36b6f6323a
1 changed files with 215 additions and 180 deletions
|
@ -150,14 +150,209 @@ fn set_pixel_precision(transform: &mut Matrix, bounds: &mut Bounds) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn propagate_transform(
|
||||||
|
entry: TransformEntry,
|
||||||
|
pixel_precision: bool,
|
||||||
|
state: &State,
|
||||||
|
entries: &mut VecDeque<Modifier>,
|
||||||
|
bounds: &mut HashMap<Uuid, Bounds>,
|
||||||
|
modifiers: &mut HashMap<Uuid, Matrix>,
|
||||||
|
) {
|
||||||
|
let Some(shape) = state.shapes.get(&entry.id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
|
let font_col = state.render_state.fonts.font_collection();
|
||||||
|
|
||||||
|
let shape_bounds_before = bounds.find(shape);
|
||||||
|
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
|
||||||
|
|
||||||
|
let mut transform = entry.transform;
|
||||||
|
|
||||||
|
if let Type::Text(content) = &shape.shape_type {
|
||||||
|
if content.grow_type() == GrowType::AutoHeight {
|
||||||
|
let mut paragraphs = content.get_skia_paragraphs(font_col);
|
||||||
|
set_paragraphs_width(shape_bounds_after.width(), &mut paragraphs);
|
||||||
|
let height = auto_height(¶graphs);
|
||||||
|
let resize_transform = math::resize_matrix(
|
||||||
|
&shape_bounds_after,
|
||||||
|
&shape_bounds_after,
|
||||||
|
shape_bounds_after.width(),
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
||||||
|
transform.post_concat(&resize_transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pixel_precision {
|
||||||
|
set_pixel_precision(&mut transform, &mut shape_bounds_after);
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.propagate {
|
||||||
|
let mut children = propagate_children(
|
||||||
|
shape,
|
||||||
|
shapes,
|
||||||
|
&shape_bounds_before,
|
||||||
|
&shape_bounds_after,
|
||||||
|
transform,
|
||||||
|
bounds,
|
||||||
|
&state.structure,
|
||||||
|
&state.scale_content,
|
||||||
|
);
|
||||||
|
entries.append(&mut children);
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds.insert(shape.id, shape_bounds_after);
|
||||||
|
|
||||||
|
let mut shape_modif = modifiers.get(&shape.id).copied().unwrap_or_default();
|
||||||
|
shape_modif.post_concat(&transform);
|
||||||
|
modifiers.insert(shape.id, shape_modif);
|
||||||
|
|
||||||
|
if shape.has_layout() {
|
||||||
|
entries.push_back(Modifier::reflow(shape.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
||||||
|
if parent.has_layout() || parent.is_group_like() {
|
||||||
|
entries.push_back(Modifier::reflow(parent.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn propagate_reflow(
|
||||||
|
id: &Uuid,
|
||||||
|
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;
|
||||||
|
|
||||||
|
match &shape.shape_type {
|
||||||
|
Type::Frame(Frame {
|
||||||
|
layout: Some(_), ..
|
||||||
|
}) => {
|
||||||
|
if !reflown.contains(id) {
|
||||||
|
let mut skip_reflow = false;
|
||||||
|
if shape.is_layout_horizontal_fill() || shape.is_layout_vertical_fill() {
|
||||||
|
if let Some(parent_id) = shape.parent_id {
|
||||||
|
if !reflown.contains(&parent_id) {
|
||||||
|
// If this is a fill layout but the parent has not been reflown yet
|
||||||
|
// we wait for the next iteration for reflow
|
||||||
|
skip_reflow = true;
|
||||||
|
reflow_parent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if shape.is_layout_vertical_auto() || shape.is_layout_horizontal_auto() {
|
||||||
|
reflow_parent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !skip_reflow {
|
||||||
|
layout_reflows.push(*id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Group(Group { masked: true }) => {
|
||||||
|
let children_ids = modified_children_ids(shape, state.structure.get(&shape.id), true);
|
||||||
|
if let Some(child) = shapes.get(&children_ids[0]) {
|
||||||
|
let child_bounds = bounds.find(child);
|
||||||
|
bounds.insert(shape.id, child_bounds);
|
||||||
|
reflow_parent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Group(_) => {
|
||||||
|
if let Some(shape_bounds) =
|
||||||
|
calculate_group_bounds(shape, shapes, bounds, &state.structure)
|
||||||
|
{
|
||||||
|
bounds.insert(shape.id, shape_bounds);
|
||||||
|
reflow_parent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Bool(_) => {
|
||||||
|
// TODO: How to calculate from rust the new box? we need to calculate the
|
||||||
|
// new path... impossible right now. I'm going to use for the moment the group
|
||||||
|
// calculation
|
||||||
|
if let Some(shape_bounds) =
|
||||||
|
calculate_group_bounds(shape, shapes, bounds, &state.structure)
|
||||||
|
{
|
||||||
|
bounds.insert(shape.id, shape_bounds);
|
||||||
|
reflow_parent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Other shapes don't have to be reflown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
||||||
|
if reflow_parent && (parent.has_layout() || parent.is_group_like()) {
|
||||||
|
entries.push_back(Modifier::reflow(parent.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let shapes = &state.shapes;
|
||||||
|
|
||||||
|
let shape = if let Some(scale_content) = state.scale_content.get(id) {
|
||||||
|
&shape.scale_content(*scale_content)
|
||||||
|
} else {
|
||||||
|
shape
|
||||||
|
};
|
||||||
|
|
||||||
|
let Type::Frame(frame_data) = &shape.shape_type else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
|
||||||
|
let mut children = flex_layout::reflow_flex_layout(
|
||||||
|
shape,
|
||||||
|
layout_data,
|
||||||
|
flex_data,
|
||||||
|
shapes,
|
||||||
|
bounds,
|
||||||
|
&state.structure,
|
||||||
|
);
|
||||||
|
entries.append(&mut children);
|
||||||
|
} else if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
|
||||||
|
let mut children = grid_layout::reflow_grid_layout(
|
||||||
|
shape,
|
||||||
|
layout_data,
|
||||||
|
grid_data,
|
||||||
|
shapes,
|
||||||
|
bounds,
|
||||||
|
&state.structure,
|
||||||
|
);
|
||||||
|
entries.append(&mut children);
|
||||||
|
}
|
||||||
|
reflown.insert(*id);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn propagate_modifiers(
|
pub fn propagate_modifiers(
|
||||||
state: &State,
|
state: &State,
|
||||||
modifiers: &[TransformEntry],
|
modifiers: &[TransformEntry],
|
||||||
pixel_precision: bool,
|
pixel_precision: bool,
|
||||||
) -> Vec<TransformEntry> {
|
) -> Vec<TransformEntry> {
|
||||||
let shapes = &state.shapes;
|
|
||||||
|
|
||||||
let font_col = state.render_state.fonts.font_collection();
|
|
||||||
let mut entries: VecDeque<_> = modifiers
|
let mut entries: VecDeque<_> = modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| Modifier::Transform(entry.clone()))
|
.map(|entry| Modifier::Transform(entry.clone()))
|
||||||
|
@ -171,7 +366,6 @@ pub fn propagate_modifiers(
|
||||||
|
|
||||||
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
||||||
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
let mut bounds = HashMap::<Uuid, Bounds>::new();
|
||||||
|
|
||||||
let mut reflown = HashSet::<Uuid>::new();
|
let mut reflown = HashSet::<Uuid>::new();
|
||||||
let mut layout_reflows = Vec::<Uuid>::new();
|
let mut layout_reflows = Vec::<Uuid>::new();
|
||||||
|
|
||||||
|
@ -183,143 +377,22 @@ pub fn propagate_modifiers(
|
||||||
while !entries.is_empty() {
|
while !entries.is_empty() {
|
||||||
while let Some(modifier) = entries.pop_front() {
|
while let Some(modifier) = entries.pop_front() {
|
||||||
match modifier {
|
match modifier {
|
||||||
Modifier::Transform(entry) => {
|
Modifier::Transform(entry) => propagate_transform(
|
||||||
let Some(shape) = state.shapes.get(&entry.id) else {
|
entry,
|
||||||
continue;
|
pixel_precision,
|
||||||
};
|
state,
|
||||||
|
&mut entries,
|
||||||
let shape_bounds_before = bounds.find(shape);
|
&mut bounds,
|
||||||
let mut shape_bounds_after = shape_bounds_before.transform(&entry.transform);
|
&mut modifiers,
|
||||||
|
),
|
||||||
let mut transform = entry.transform;
|
Modifier::Reflow(id) => propagate_reflow(
|
||||||
|
&id,
|
||||||
if let Type::Text(content) = &shape.shape_type {
|
state,
|
||||||
if content.grow_type() == GrowType::AutoHeight {
|
&mut entries,
|
||||||
let mut paragraphs = content.get_skia_paragraphs(font_col);
|
&mut bounds,
|
||||||
set_paragraphs_width(shape_bounds_after.width(), &mut paragraphs);
|
&mut layout_reflows,
|
||||||
let height = auto_height(¶graphs);
|
&mut reflown,
|
||||||
let resize_transform = math::resize_matrix(
|
),
|
||||||
&shape_bounds_after,
|
|
||||||
&shape_bounds_after,
|
|
||||||
shape_bounds_after.width(),
|
|
||||||
height,
|
|
||||||
);
|
|
||||||
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
|
||||||
transform.post_concat(&resize_transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if pixel_precision {
|
|
||||||
set_pixel_precision(&mut transform, &mut shape_bounds_after);
|
|
||||||
}
|
|
||||||
|
|
||||||
if entry.propagate {
|
|
||||||
let mut children = propagate_children(
|
|
||||||
shape,
|
|
||||||
shapes,
|
|
||||||
&shape_bounds_before,
|
|
||||||
&shape_bounds_after,
|
|
||||||
transform,
|
|
||||||
&bounds,
|
|
||||||
&state.structure,
|
|
||||||
&state.scale_content,
|
|
||||||
);
|
|
||||||
entries.append(&mut children);
|
|
||||||
}
|
|
||||||
|
|
||||||
bounds.insert(shape.id, shape_bounds_after);
|
|
||||||
|
|
||||||
let mut shape_modif = modifiers.get(&shape.id).copied().unwrap_or_default();
|
|
||||||
shape_modif.post_concat(&transform);
|
|
||||||
modifiers.insert(shape.id, shape_modif);
|
|
||||||
|
|
||||||
if shape.has_layout() {
|
|
||||||
entries.push_back(Modifier::reflow(shape.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
|
||||||
if parent.has_layout() || parent.is_group_like() {
|
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Modifier::Reflow(id) => {
|
|
||||||
let Some(shape) = state.shapes.get(&id) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut reflow_parent = false;
|
|
||||||
|
|
||||||
match &shape.shape_type {
|
|
||||||
Type::Frame(Frame {
|
|
||||||
layout: Some(_), ..
|
|
||||||
}) => {
|
|
||||||
if !reflown.contains(&id) {
|
|
||||||
let mut skip_reflow = false;
|
|
||||||
if shape.is_layout_horizontal_fill()
|
|
||||||
|| shape.is_layout_vertical_fill()
|
|
||||||
{
|
|
||||||
if let Some(parent_id) = shape.parent_id {
|
|
||||||
if !reflown.contains(&parent_id) {
|
|
||||||
// If this is a fill layout but the parent has not been reflown yet
|
|
||||||
// we wait for the next iteration for reflow
|
|
||||||
skip_reflow = true;
|
|
||||||
reflow_parent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if shape.is_layout_vertical_auto()
|
|
||||||
|| shape.is_layout_horizontal_auto()
|
|
||||||
{
|
|
||||||
reflow_parent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !skip_reflow {
|
|
||||||
layout_reflows.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type::Group(Group { masked: true }) => {
|
|
||||||
let children_ids =
|
|
||||||
modified_children_ids(shape, state.structure.get(&shape.id), true);
|
|
||||||
if let Some(child) = shapes.get(&children_ids[0]) {
|
|
||||||
let child_bounds = bounds.find(child);
|
|
||||||
bounds.insert(shape.id, child_bounds);
|
|
||||||
reflow_parent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type::Group(_) => {
|
|
||||||
if let Some(shape_bounds) =
|
|
||||||
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
|
|
||||||
{
|
|
||||||
bounds.insert(shape.id, shape_bounds);
|
|
||||||
reflow_parent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type::Bool(_) => {
|
|
||||||
// TODO: How to calculate from rust the new box? we need to calculate the
|
|
||||||
// new path... impossible right now. I'm going to use for the moment the group
|
|
||||||
// calculation
|
|
||||||
if let Some(shape_bounds) =
|
|
||||||
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
|
|
||||||
{
|
|
||||||
bounds.insert(shape.id, shape_bounds);
|
|
||||||
reflow_parent = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Other shapes don't have to be reflown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
|
||||||
if reflow_parent && (parent.has_layout() || parent.is_group_like()) {
|
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,45 +400,7 @@ pub fn propagate_modifiers(
|
||||||
if reflown.contains(id) {
|
if reflown.contains(id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
reflow_shape(id, state, &mut reflown, &mut entries, &mut bounds);
|
||||||
let Some(shape) = state.shapes.get(id) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let shape = if let Some(scale_content) = state.scale_content.get(id) {
|
|
||||||
&shape.scale_content(*scale_content)
|
|
||||||
} else {
|
|
||||||
shape
|
|
||||||
};
|
|
||||||
|
|
||||||
let Type::Frame(frame_data) = &shape.shape_type else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(Layout::FlexLayout(layout_data, flex_data)) = &frame_data.layout {
|
|
||||||
let mut children = flex_layout::reflow_flex_layout(
|
|
||||||
shape,
|
|
||||||
layout_data,
|
|
||||||
flex_data,
|
|
||||||
shapes,
|
|
||||||
&mut bounds,
|
|
||||||
&state.structure,
|
|
||||||
);
|
|
||||||
entries.append(&mut children);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Layout::GridLayout(layout_data, grid_data)) = &frame_data.layout {
|
|
||||||
let mut children = grid_layout::reflow_grid_layout(
|
|
||||||
shape,
|
|
||||||
layout_data,
|
|
||||||
grid_data,
|
|
||||||
shapes,
|
|
||||||
&mut bounds,
|
|
||||||
&state.structure,
|
|
||||||
);
|
|
||||||
entries.append(&mut children);
|
|
||||||
}
|
|
||||||
reflown.insert(*id);
|
|
||||||
}
|
}
|
||||||
layout_reflows = Vec::new();
|
layout_reflows = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue