Reparent modifiers

This commit is contained in:
alonso.torres 2025-04-16 11:00:33 +02:00
parent f3d13005b2
commit daf048e258
10 changed files with 283 additions and 52 deletions

View file

@ -8,7 +8,8 @@ use common::GetBounds;
use crate::math::{identitish, Bounds, Matrix, Point};
use crate::shapes::{
ConstraintH, ConstraintV, Frame, Group, Layout, Modifier, Shape, TransformEntry, Type,
modified_children_ids, ConstraintH, ConstraintV, Frame, Group, Layout, Modifier, Shape,
StructureEntry, TransformEntry, Type,
};
use crate::state::State;
use crate::uuid::Uuid;
@ -20,14 +21,17 @@ fn propagate_children(
parent_bounds_after: &Bounds,
transform: Matrix,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> {
if shape.children.len() == 0 || identitish(transform) {
let children_ids = modified_children_ids(shape, structure.get(&shape.id));
if children_ids.len() == 0 || identitish(transform) {
return VecDeque::new();
}
let mut result = VecDeque::new();
for child_id in shape.children.iter() {
for child_id in children_ids.iter() {
let Some(child) = shapes.get(child_id) else {
continue;
};
@ -81,10 +85,13 @@ fn calculate_group_bounds(
shape: &Shape,
shapes: &HashMap<Uuid, Shape>,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Option<Bounds> {
let shape_bounds = bounds.find(&shape);
let mut result = Vec::<Point>::new();
for child_id in shape.children.iter() {
let children_ids = modified_children_ids(shape, structure.get(&shape.id));
for child_id in children_ids.iter() {
let Some(child) = shapes.get(child_id) else {
continue;
};
@ -103,6 +110,13 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
.iter()
.map(|entry| Modifier::Transform(entry.clone()))
.collect();
for (id, _) in &state.structure {
if id != &Uuid::nil() {
entries.push_back(Modifier::Reflow(*id));
}
}
let mut modifiers = HashMap::<Uuid, Matrix>::new();
let mut bounds = HashMap::<Uuid, Bounds>::new();
@ -133,6 +147,7 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
&shape_bounds_after,
entry.transform,
&bounds,
&state.structure,
);
entries.append(&mut children);
@ -191,7 +206,9 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
}
}
Type::Group(Group { masked: true }) => {
if let Some(child) = shapes.get(&shape.children[0]) {
let children_ids =
modified_children_ids(shape, state.structure.get(&shape.id));
if let Some(child) = shapes.get(&children_ids[0]) {
let child_bounds = bounds.find(&child);
bounds.insert(shape.id, child_bounds);
reflow_parent = true;
@ -199,7 +216,7 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
}
Type::Group(_) => {
if let Some(shape_bounds) =
calculate_group_bounds(shape, shapes, &bounds)
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
{
bounds.insert(shape.id, shape_bounds);
reflow_parent = true;
@ -210,7 +227,7 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
// 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)
calculate_group_bounds(shape, shapes, &bounds, &state.structure)
{
bounds.insert(shape.id, shape_bounds);
reflow_parent = true;
@ -250,6 +267,7 @@ pub fn propagate_modifiers(state: &State, modifiers: Vec<TransformEntry>) -> Vec
flex_data,
shapes,
&mut bounds,
&state.structure,
);
entries.append(&mut children);
}
@ -313,7 +331,8 @@ mod tests {
&bounds_before,
&bounds_after,
transform,
&HashMap::<Uuid, Bounds>::new(),
&HashMap::new(),
&HashMap::new(),
);
assert_eq!(result.len(), 1);
@ -342,7 +361,7 @@ mod tests {
shapes.insert(parent_id, parent.clone());
let bounds =
calculate_group_bounds(&parent, &shapes, &HashMap::<Uuid, Bounds>::new()).unwrap();
calculate_group_bounds(&parent, &shapes, &HashMap::new(), &HashMap::new()).unwrap();
assert_eq!(bounds.width(), 3.0);
assert_eq!(bounds.height(), 3.0);

View file

@ -1,8 +1,8 @@
#![allow(dead_code)]
use crate::math::{self as math, Bounds, Matrix, Point, Vector, VectorExt};
use crate::shapes::{
AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent, LayoutData, LayoutItem,
Modifier, Shape,
modified_children_ids, AlignContent, AlignItems, AlignSelf, FlexData, JustifyContent,
LayoutData, LayoutItem, Modifier, Shape, StructureEntry,
};
use crate::uuid::Uuid;
@ -180,10 +180,11 @@ fn initialize_tracks(
flex_data: &FlexData,
shapes: &HashMap<Uuid, Shape>,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Vec<TrackData> {
let mut tracks = Vec::<TrackData>::new();
let mut current_track = TrackData::default();
let mut children = shape.children.clone();
let mut children = modified_children_ids(shape, structure.get(&shape.id));
let mut first = true;
if !flex_data.is_reverse() {
@ -421,6 +422,7 @@ fn calculate_track_data(
layout_bounds: &Bounds,
shapes: &HashMap<Uuid, Shape>,
bounds: &HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> Vec<TrackData> {
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
let mut tracks = initialize_tracks(
@ -430,6 +432,7 @@ fn calculate_track_data(
flex_data,
shapes,
bounds,
structure,
);
if !layout_axis.is_auto_main {
@ -550,11 +553,20 @@ pub fn reflow_flex_layout(
flex_data: &FlexData,
shapes: &HashMap<Uuid, Shape>,
bounds: &mut HashMap<Uuid, Bounds>,
structure: &HashMap<Uuid, Vec<StructureEntry>>,
) -> VecDeque<Modifier> {
let mut result = VecDeque::new();
let layout_bounds = &bounds.find(&shape);
let layout_axis = LayoutAxis::new(shape, layout_bounds, layout_data, flex_data);
let tracks = calculate_track_data(shape, layout_data, flex_data, layout_bounds, shapes, bounds);
let tracks = calculate_track_data(
shape,
layout_data,
flex_data,
layout_bounds,
shapes,
bounds,
structure,
);
for track in tracks.iter() {
let total_shapes_size = track.shapes.iter().map(|s| s.main_size).sum::<f32>();

View file

@ -98,6 +98,66 @@ impl SerializableResult for TransformEntry {
}
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum StructureEntryType {
RemoveChild,
AddChild,
}
impl StructureEntryType {
pub fn from_u32(value: u32) -> Self {
match value {
1 => Self::RemoveChild,
2 => Self::AddChild,
_ => unreachable!(),
}
}
}
#[derive(PartialEq, Debug, Clone)]
#[repr(C)]
pub struct StructureEntry {
pub entry_type: StructureEntryType,
pub index: u32,
pub parent: Uuid,
pub id: Uuid,
}
impl StructureEntry {
pub fn new(entry_type: StructureEntryType, index: u32, parent: Uuid, id: Uuid) -> Self {
StructureEntry {
entry_type,
index,
parent,
id,
}
}
pub fn from_bytes(bytes: [u8; 40]) -> Self {
let entry_type = StructureEntryType::from_u32(u32::from_le_bytes([
bytes[0], bytes[1], bytes[2], bytes[3],
]));
let index = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
let parent = uuid_from_u32_quartet(
u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]),
u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
u32::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]),
u32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]),
);
let id = uuid_from_u32_quartet(
u32::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]),
u32::from_le_bytes([bytes[28], bytes[29], bytes[30], bytes[31]]),
u32::from_le_bytes([bytes[32], bytes[33], bytes[34], bytes[35]]),
u32::from_le_bytes([bytes[36], bytes[37], bytes[38], bytes[39]]),
);
StructureEntry::new(entry_type, index, parent, id)
}
}
#[cfg(test)]
mod tests {
use super::*;