mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
✨ Improved performance in modifiers
This commit is contained in:
@@ -767,6 +767,11 @@
|
|||||||
:always
|
:always
|
||||||
(ctl/update-flex-child value))))
|
(ctl/update-flex-child value))))
|
||||||
|
|
||||||
|
(defn remove-children-set
|
||||||
|
[shapes children-to-remove]
|
||||||
|
(let [remove? (set children-to-remove)]
|
||||||
|
(d/removev remove? shapes)))
|
||||||
|
|
||||||
(defn apply-modifier
|
(defn apply-modifier
|
||||||
[shape operation]
|
[shape operation]
|
||||||
(let [type (dm/get-prop operation :type)]
|
(let [type (dm/get-prop operation :type)]
|
||||||
@@ -793,7 +798,7 @@
|
|||||||
|
|
||||||
:remove-children
|
:remove-children
|
||||||
(let [value (dm/get-prop operation :value)]
|
(let [value (dm/get-prop operation :value)]
|
||||||
(update shape :shapes remove-children value))
|
(update shape :shapes remove-children-set value))
|
||||||
|
|
||||||
:scale-content
|
:scale-content
|
||||||
(let [value (dm/get-prop operation :value)]
|
(let [value (dm/get-prop operation :value)]
|
||||||
@@ -810,11 +815,6 @@
|
|||||||
(defn apply-structure-modifiers
|
(defn apply-structure-modifiers
|
||||||
"Apply structure changes to a shape"
|
"Apply structure changes to a shape"
|
||||||
[shape modifiers]
|
[shape modifiers]
|
||||||
(let [remove-children
|
(as-> shape $
|
||||||
(fn [shapes children-to-remove]
|
(reduce apply-modifier $ (dm/get-prop modifiers :structure-parent))
|
||||||
(let [remove? (set children-to-remove)]
|
(reduce apply-modifier $ (dm/get-prop modifiers :structure-child))))
|
||||||
(d/removev remove? shapes)))]
|
|
||||||
|
|
||||||
(as-> shape $
|
|
||||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-parent))
|
|
||||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-child)))))
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.types.modifiers :as ctm]
|
|
||||||
[app.common.types.path :as path]
|
[app.common.types.path :as path]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.types.shape.attrs :refer [editable-attrs]]
|
[app.common.types.shape.attrs :refer [editable-attrs]]
|
||||||
|
|||||||
@@ -51,6 +51,13 @@ pub fn identitish(m: &Matrix) -> bool {
|
|||||||
&& is_close_to(m.skew_y(), 0.0)
|
&& is_close_to(m.skew_y(), 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_move_only_matrix(m: &Matrix) -> bool {
|
||||||
|
is_close_to(m.scale_x(), 1.0)
|
||||||
|
&& is_close_to(m.scale_y(), 1.0)
|
||||||
|
&& is_close_to(m.skew_x(), 0.0)
|
||||||
|
&& is_close_to(m.skew_y(), 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct Bounds {
|
pub struct Bounds {
|
||||||
pub nw: Point,
|
pub nw: Point,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use skia_safe::{self as skia};
|
use skia_safe::{self as skia};
|
||||||
|
|
||||||
|
use indexmap::IndexSet;
|
||||||
|
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
@@ -342,9 +344,14 @@ impl Shape {
|
|||||||
matches!(
|
matches!(
|
||||||
self.shape_type,
|
self.shape_type,
|
||||||
Type::Frame(Frame {
|
Type::Frame(Frame {
|
||||||
layout: Some(layouts::Layout::FlexLayout(_, FlexData {
|
layout: Some(layouts::Layout::FlexLayout(
|
||||||
direction: layouts::FlexDirection::RowReverse | layouts::FlexDirection::ColumnReverse, ..
|
_,
|
||||||
})),
|
FlexData {
|
||||||
|
direction: layouts::FlexDirection::RowReverse
|
||||||
|
| layouts::FlexDirection::ColumnReverse,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
)),
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -1279,13 +1286,14 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_structure(&mut self, structure: &Vec<StructureEntry>) {
|
pub fn apply_structure(&mut self, structure: &Vec<StructureEntry>) {
|
||||||
let mut result: Vec<Uuid> = Vec::from_iter(self.children.iter().copied());
|
let mut result = IndexSet::<Uuid>::from_iter(self.children.iter().copied());
|
||||||
let mut to_remove = HashSet::<&Uuid>::new();
|
let mut to_remove = HashSet::<&Uuid>::new();
|
||||||
|
|
||||||
for st in structure {
|
for st in structure {
|
||||||
match st.entry_type {
|
match st.entry_type {
|
||||||
StructureEntryType::AddChild => {
|
StructureEntryType::AddChild => {
|
||||||
result.insert(st.index as usize, st.id);
|
let index = usize::min(result.len() - 1, st.index as usize);
|
||||||
|
result.shift_insert(index, st.id);
|
||||||
}
|
}
|
||||||
StructureEntryType::RemoveChild => {
|
StructureEntryType::RemoveChild => {
|
||||||
to_remove.insert(&st.id);
|
to_remove.insert(&st.id);
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ mod flex_layout;
|
|||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod grid_layout;
|
pub mod grid_layout;
|
||||||
|
|
||||||
use crate::math::{self as math, bools, identitish, Bounds, Matrix, Point};
|
use crate::math::{self as math, bools, identitish, is_close_to, Bounds, Matrix, Point};
|
||||||
use common::GetBounds;
|
use common::GetBounds;
|
||||||
|
|
||||||
use crate::shapes::{
|
use crate::shapes::{
|
||||||
ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, TransformEntry, Type,
|
ConstraintH, ConstraintV, Frame, Group, GrowType, Layout, Modifier, Shape, TransformEntry,
|
||||||
|
TransformEntrySource, Type,
|
||||||
};
|
};
|
||||||
use crate::state::{ShapesPoolRef, State};
|
use crate::state::{ShapesPoolRef, State};
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
@@ -75,7 +76,7 @@ fn propagate_children(
|
|||||||
child.ignore_constraints,
|
child.ignore_constraints,
|
||||||
);
|
);
|
||||||
|
|
||||||
result.push_back(Modifier::transform(*child_id, transform));
|
result.push_back(Modifier::transform_propagate(*child_id, transform));
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@@ -182,33 +183,43 @@ fn propagate_transform(
|
|||||||
|
|
||||||
let mut transform = entry.transform;
|
let mut transform = entry.transform;
|
||||||
|
|
||||||
// NOTA: No puedo utilizar un clone porque entonces estaríamos
|
// Only check the text layout when the width/height changes
|
||||||
// perdiendo la referencia al contenido del layout...
|
if !is_close_to(shape_bounds_before.width(), shape_bounds_after.width())
|
||||||
if let Type::Text(text_content) = &mut shape.shape_type.clone() {
|
|| !is_close_to(shape_bounds_before.height(), shape_bounds_after.height())
|
||||||
if text_content.needs_update_layout() {
|
{
|
||||||
text_content.update_layout(shape.selrect);
|
if let Type::Text(text_content) = &mut shape.shape_type.clone() {
|
||||||
}
|
match text_content.grow_type() {
|
||||||
match text_content.grow_type() {
|
GrowType::AutoHeight => {
|
||||||
GrowType::AutoHeight => {
|
if text_content.needs_update_layout() {
|
||||||
let height = text_content.size.height;
|
text_content.update_layout(shape.selrect);
|
||||||
let resize_transform = math::resize_matrix(
|
}
|
||||||
&shape_bounds_after,
|
let height = text_content.size.height;
|
||||||
&shape_bounds_after,
|
let resize_transform = math::resize_matrix(
|
||||||
shape_bounds_after.width(),
|
&shape_bounds_after,
|
||||||
height,
|
&shape_bounds_after,
|
||||||
);
|
shape_bounds_after.width(),
|
||||||
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
height,
|
||||||
transform.post_concat(&resize_transform);
|
);
|
||||||
|
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
||||||
|
transform.post_concat(&resize_transform);
|
||||||
|
}
|
||||||
|
GrowType::AutoWidth => {
|
||||||
|
if text_content.needs_update_layout() {
|
||||||
|
text_content.update_layout(shape.selrect);
|
||||||
|
}
|
||||||
|
let width = text_content.width();
|
||||||
|
let height = text_content.size.height;
|
||||||
|
let resize_transform = math::resize_matrix(
|
||||||
|
&shape_bounds_after,
|
||||||
|
&shape_bounds_after,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
||||||
|
transform.post_concat(&resize_transform);
|
||||||
|
}
|
||||||
|
GrowType::Fixed => {}
|
||||||
}
|
}
|
||||||
GrowType::AutoWidth => {
|
|
||||||
let width = text_content.width();
|
|
||||||
let height = text_content.size.height;
|
|
||||||
let resize_transform =
|
|
||||||
math::resize_matrix(&shape_bounds_after, &shape_bounds_after, width, height);
|
|
||||||
shape_bounds_after = shape_bounds_after.transform(&resize_transform);
|
|
||||||
transform.post_concat(&resize_transform);
|
|
||||||
}
|
|
||||||
GrowType::Fixed => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,12 +245,19 @@ fn propagate_transform(
|
|||||||
shape_modif.post_concat(&transform);
|
shape_modif.post_concat(&transform);
|
||||||
modifiers.insert(shape.id, shape_modif);
|
modifiers.insert(shape.id, shape_modif);
|
||||||
|
|
||||||
if shape.has_layout() {
|
let is_resize = !math::is_move_only_matrix(&transform);
|
||||||
|
let is_propagate = entry.source == TransformEntrySource::Propagate;
|
||||||
|
|
||||||
|
// If this is a layout and we're only moving don't need to reflow
|
||||||
|
if shape.has_layout() && is_resize {
|
||||||
entries.push_back(Modifier::reflow(shape.id));
|
entries.push_back(Modifier::reflow(shape.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
if let Some(parent) = shape.parent_id.and_then(|id| shapes.get(&id)) {
|
||||||
if parent.has_layout() || parent.is_group_like() {
|
// When the parent is either a group or a layout we only mark for reflow
|
||||||
|
// if the current transformation is not a move propagation.
|
||||||
|
// If it's a move propagation we don't need to reflow, the parent is already changed.
|
||||||
|
if (parent.has_layout() || parent.is_group_like()) && (is_resize || !is_propagate) {
|
||||||
entries.push_back(Modifier::reflow(parent.id));
|
entries.push_back(Modifier::reflow(parent.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +378,14 @@ pub fn propagate_modifiers(
|
|||||||
) -> Vec<TransformEntry> {
|
) -> Vec<TransformEntry> {
|
||||||
let mut entries: VecDeque<_> = modifiers
|
let mut entries: VecDeque<_> = modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| Modifier::Transform(entry.clone()))
|
.map(|entry| {
|
||||||
|
// If we receibe a identity matrix we force a reflow
|
||||||
|
if math::identitish(&entry.transform) {
|
||||||
|
Modifier::Reflow(entry.id)
|
||||||
|
} else {
|
||||||
|
Modifier::Transform(entry.clone())
|
||||||
|
}
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
||||||
@@ -407,7 +432,7 @@ pub fn propagate_modifiers(
|
|||||||
|
|
||||||
modifiers
|
modifiers
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, val)| TransformEntry::new(*key, *val))
|
.map(|(key, val)| TransformEntry::from_input(*key, *val))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::math::{Bounds, Matrix};
|
use crate::math::{is_move_only_matrix, Bounds, Matrix};
|
||||||
use crate::shapes::{ConstraintH, ConstraintV};
|
use crate::shapes::{ConstraintH, ConstraintV};
|
||||||
|
|
||||||
pub fn calculate_resize(
|
pub fn calculate_resize(
|
||||||
@@ -110,7 +110,7 @@ pub fn propagate_shape_constraints(
|
|||||||
// can propagate as is
|
// can propagate as is
|
||||||
if (ignore_constrainst
|
if (ignore_constrainst
|
||||||
|| constraint_h == ConstraintH::Scale && constraint_v == ConstraintV::Scale)
|
|| constraint_h == ConstraintH::Scale && constraint_v == ConstraintV::Scale)
|
||||||
|| transform.is_translate()
|
|| is_move_only_matrix(&transform)
|
||||||
{
|
{
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -623,7 +623,7 @@ pub fn reflow_flex_layout(
|
|||||||
transform.post_concat(&Matrix::translate(delta_v));
|
transform.post_concat(&Matrix::translate(delta_v));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push_back(Modifier::transform(child.id, transform));
|
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||||
|
|
||||||
shape_anchor = next_anchor(
|
shape_anchor = next_anchor(
|
||||||
layout_data,
|
layout_data,
|
||||||
|
|||||||
@@ -791,7 +791,7 @@ pub fn reflow_grid_layout(
|
|||||||
transform.post_concat(&Matrix::translate(delta_v));
|
transform.post_concat(&Matrix::translate(delta_v));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push_back(Modifier::transform(child.id, transform));
|
result.push_back(Modifier::transform_propagate(child.id, transform));
|
||||||
}
|
}
|
||||||
|
|
||||||
if shape.is_layout_horizontal_auto() || shape.is_layout_vertical_auto() {
|
if shape.is_layout_horizontal_auto() || shape.is_layout_vertical_auto() {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ pub enum Modifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Modifier {
|
impl Modifier {
|
||||||
pub fn transform(id: Uuid, transform: Matrix) -> Self {
|
pub fn transform_propagate(id: Uuid, transform: Matrix) -> Self {
|
||||||
Modifier::Transform(TransformEntry::new(id, transform))
|
Modifier::Transform(TransformEntry::from_propagate(id, transform))
|
||||||
}
|
}
|
||||||
pub fn parent(id: Uuid, transform: Matrix) -> Self {
|
pub fn parent(id: Uuid, transform: Matrix) -> Self {
|
||||||
Modifier::Transform(TransformEntry::parent(id, transform))
|
Modifier::Transform(TransformEntry::parent(id, transform))
|
||||||
@@ -23,19 +23,35 @@ impl Modifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub enum TransformEntrySource {
|
||||||
|
Input,
|
||||||
|
Propagate,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Clone)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TransformEntry {
|
pub struct TransformEntry {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub transform: Matrix,
|
pub transform: Matrix,
|
||||||
|
pub source: TransformEntrySource,
|
||||||
pub propagate: bool,
|
pub propagate: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransformEntry {
|
impl TransformEntry {
|
||||||
pub fn new(id: Uuid, transform: Matrix) -> Self {
|
pub fn from_input(id: Uuid, transform: Matrix) -> Self {
|
||||||
TransformEntry {
|
TransformEntry {
|
||||||
id,
|
id,
|
||||||
transform,
|
transform,
|
||||||
|
source: TransformEntrySource::Input,
|
||||||
|
propagate: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_propagate(id: Uuid, transform: Matrix) -> Self {
|
||||||
|
TransformEntry {
|
||||||
|
id,
|
||||||
|
transform,
|
||||||
|
source: TransformEntrySource::Propagate,
|
||||||
propagate: true,
|
propagate: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +59,7 @@ impl TransformEntry {
|
|||||||
TransformEntry {
|
TransformEntry {
|
||||||
id,
|
id,
|
||||||
transform,
|
transform,
|
||||||
|
source: TransformEntrySource::Propagate,
|
||||||
propagate: false,
|
propagate: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +87,7 @@ impl SerializableResult for TransformEntry {
|
|||||||
0.0,
|
0.0,
|
||||||
1.0,
|
1.0,
|
||||||
);
|
);
|
||||||
TransformEntry::new(id, transform)
|
TransformEntry::from_input(id, transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bytes(&self) -> Self::BytesType {
|
fn as_bytes(&self) -> Self::BytesType {
|
||||||
@@ -176,7 +193,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
let entry = TransformEntry::new(
|
let entry = TransformEntry::from_input(
|
||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
Matrix::new_all(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.0, 0.0, 1.0),
|
Matrix::new_all(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.0, 0.0, 1.0),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user