mirror of https://github.com/penpot/penpot.git
Merge pull request #7730 from penpot/alotor-fixes-layouts
✨ Fix new render problems with layout
This commit is contained in:
commit
8aaa953604
|
|
@ -732,89 +732,89 @@
|
|||
[shape scale-text-content value]
|
||||
(update shape :content scale-text-content value))
|
||||
|
||||
(defn scale-text-content
|
||||
[content value]
|
||||
(->> content
|
||||
(txt/transform-nodes txt/is-text-node? (partial transform-text-node value))
|
||||
(txt/transform-nodes txt/is-paragraph-node? (partial transform-paragraph-node value))))
|
||||
|
||||
(defn apply-scale-content
|
||||
[shape value]
|
||||
;; Scale can only be positive
|
||||
(let [value (mth/abs value)]
|
||||
(cond-> shape
|
||||
(cfh/text-shape? shape)
|
||||
(update-text-content scale-text-content value)
|
||||
|
||||
:always
|
||||
(gsc/update-corners-scale value)
|
||||
|
||||
(d/not-empty? (:strokes shape))
|
||||
(gss/update-strokes-width value)
|
||||
|
||||
(d/not-empty? (:shadow shape))
|
||||
(gse/update-shadows-scale value)
|
||||
|
||||
(some? (:blur shape))
|
||||
(gse/update-blur-scale value)
|
||||
|
||||
(ctl/flex-layout? shape)
|
||||
(ctl/update-flex-scale value)
|
||||
|
||||
(ctl/grid-layout? shape)
|
||||
(ctl/update-grid-scale value)
|
||||
|
||||
:always
|
||||
(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
|
||||
[shape operation]
|
||||
(let [type (dm/get-prop operation :type)]
|
||||
(case type
|
||||
:rotation
|
||||
(let [rotation (dm/get-prop operation :value)]
|
||||
(update shape :rotation #(mod (+ (or % 0) rotation) 360)))
|
||||
|
||||
:add-children
|
||||
(let [value (dm/get-prop operation :value)
|
||||
index (dm/get-prop operation :index)
|
||||
|
||||
shape
|
||||
(if (some? index)
|
||||
(update shape :shapes
|
||||
(fn [shapes]
|
||||
(if (vector? shapes)
|
||||
(d/insert-at-index shapes index value)
|
||||
(d/concat-vec shapes value))))
|
||||
(update shape :shapes d/concat-vec value))]
|
||||
|
||||
;; Remove duplication
|
||||
(update shape :shapes #(into [] (apply d/ordered-set %))))
|
||||
|
||||
:remove-children
|
||||
(let [value (dm/get-prop operation :value)]
|
||||
(update shape :shapes remove-children-set value))
|
||||
|
||||
:scale-content
|
||||
(let [value (dm/get-prop operation :value)]
|
||||
(apply-scale-content shape value))
|
||||
|
||||
:change-property
|
||||
(let [property (dm/get-prop operation :property)
|
||||
value (dm/get-prop operation :value)]
|
||||
(assoc shape property value))
|
||||
|
||||
;; :default => no change to shape
|
||||
shape)))
|
||||
|
||||
(defn apply-structure-modifiers
|
||||
"Apply structure changes to a shape"
|
||||
[shape modifiers]
|
||||
(letfn [(scale-text-content
|
||||
[content value]
|
||||
(->> content
|
||||
(txt/transform-nodes txt/is-text-node? (partial transform-text-node value))
|
||||
(txt/transform-nodes txt/is-paragraph-node? (partial transform-paragraph-node value))))
|
||||
|
||||
(apply-scale-content
|
||||
[shape value]
|
||||
;; Scale can only be positive
|
||||
(let [value (mth/abs value)]
|
||||
(cond-> shape
|
||||
(cfh/text-shape? shape)
|
||||
(update-text-content scale-text-content value)
|
||||
|
||||
:always
|
||||
(gsc/update-corners-scale value)
|
||||
|
||||
(d/not-empty? (:strokes shape))
|
||||
(gss/update-strokes-width value)
|
||||
|
||||
(d/not-empty? (:shadow shape))
|
||||
(gse/update-shadows-scale value)
|
||||
|
||||
(some? (:blur shape))
|
||||
(gse/update-blur-scale value)
|
||||
|
||||
(ctl/flex-layout? shape)
|
||||
(ctl/update-flex-scale value)
|
||||
|
||||
(ctl/grid-layout? shape)
|
||||
(ctl/update-grid-scale value)
|
||||
|
||||
:always
|
||||
(ctl/update-flex-child value))))]
|
||||
|
||||
(let [remove-children
|
||||
(fn [shapes children-to-remove]
|
||||
(let [remove? (set children-to-remove)]
|
||||
(d/removev remove? shapes)))
|
||||
|
||||
apply-modifier
|
||||
(fn [shape operation]
|
||||
(let [type (dm/get-prop operation :type)]
|
||||
(case type
|
||||
:rotation
|
||||
(let [rotation (dm/get-prop operation :value)]
|
||||
(update shape :rotation #(mod (+ (or % 0) rotation) 360)))
|
||||
|
||||
:add-children
|
||||
(let [value (dm/get-prop operation :value)
|
||||
index (dm/get-prop operation :index)
|
||||
|
||||
shape
|
||||
(if (some? index)
|
||||
(update shape :shapes
|
||||
(fn [shapes]
|
||||
(if (vector? shapes)
|
||||
(d/insert-at-index shapes index value)
|
||||
(d/concat-vec shapes value))))
|
||||
(update shape :shapes d/concat-vec value))]
|
||||
|
||||
;; Remove duplication
|
||||
(update shape :shapes #(into [] (apply d/ordered-set %))))
|
||||
|
||||
:remove-children
|
||||
(let [value (dm/get-prop operation :value)]
|
||||
(update shape :shapes remove-children value))
|
||||
|
||||
:scale-content
|
||||
(let [value (dm/get-prop operation :value)]
|
||||
(apply-scale-content shape value))
|
||||
|
||||
:change-property
|
||||
(let [property (dm/get-prop operation :property)
|
||||
value (dm/get-prop operation :value)]
|
||||
(assoc shape property value))
|
||||
|
||||
;; :default => no change to shape
|
||||
shape)))]
|
||||
|
||||
(as-> shape $
|
||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-parent))
|
||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-child))))))
|
||||
(as-> shape $
|
||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-parent))
|
||||
(reduce apply-modifier $ (dm/get-prop modifiers :structure-child))))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.types.path :as path]))
|
||||
|
|
@ -207,3 +208,12 @@
|
|||
:projects
|
||||
(filter #(= team-id (:team-id (val %))))
|
||||
(into {}))))
|
||||
|
||||
(defn get-selrect
|
||||
[selrect-transform shape]
|
||||
(if (some? selrect-transform)
|
||||
(let [{:keys [center width height transform]} selrect-transform]
|
||||
[(gsh/center->rect center width height)
|
||||
(gmt/transform-in center transform)])
|
||||
[(dm/get-prop shape :selrect)
|
||||
(gsh/transform-matrix shape)]))
|
||||
|
|
|
|||
|
|
@ -212,13 +212,14 @@
|
|||
;; Create a new objects only with the temporary modifications
|
||||
objects-changed
|
||||
(->> wasm-props
|
||||
(group-by first)
|
||||
(reduce
|
||||
(fn [objects [id properties]]
|
||||
(let [shape
|
||||
(->> properties
|
||||
(reduce
|
||||
(fn [shape {:keys [property value]}]
|
||||
(assoc shape property value))
|
||||
(fn [shape [_ operation]]
|
||||
(ctm/apply-modifier shape operation))
|
||||
(get objects id)))]
|
||||
(assoc objects id shape)))
|
||||
objects))]
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@
|
|||
"All tokens related ephimeral state"
|
||||
(l/derived :workspace-tokens st/state))
|
||||
|
||||
(def workspace-selrect
|
||||
(l/derived :workspace-selrect st/state))
|
||||
|
||||
;; WARNING: Don't use directly from components, this is a proxy to
|
||||
;; improve performance of selected-shapes and
|
||||
(def ^:private selected-shapes-data
|
||||
|
|
|
|||
|
|
@ -7,19 +7,18 @@
|
|||
(ns app.main.ui.workspace.shapes.text.text-edition-outline
|
||||
(:require
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.features :as features]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc text-edition-outline
|
||||
[{:keys [shape zoom modifiers]}]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(let [transform (gsh/transform-str shape)
|
||||
{:keys [id x y grow-type]} shape
|
||||
{:keys [width height]} (if (= :fixed grow-type) shape (wasm.api/get-text-dimensions id))]
|
||||
(let [selrect-transform (mf/deref refs/workspace-selrect)
|
||||
[{:keys [x y width height]} transform] (dsh/get-selrect selrect-transform shape)]
|
||||
[:rect.main.viewport-selrect
|
||||
{:x x
|
||||
:y y
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.text :as gst]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.color :as color]
|
||||
[app.common.types.text :as txt]
|
||||
[app.config :as cf]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.texts :as dwt]
|
||||
[app.main.features :as features]
|
||||
|
|
@ -226,8 +228,8 @@
|
|||
(stl/css :text-editor-container))
|
||||
:ref container-ref
|
||||
:data-testid "text-editor-container"
|
||||
:style {:width (:width shape)
|
||||
:height (:height shape)}
|
||||
:style {:width "var(--editor-container-width)"
|
||||
:height "var(--editor-container-height)"}
|
||||
;; We hide the editor when is blurred because otherwise the
|
||||
;; selection won't let us see the underlying text. Use opacity
|
||||
;; because display or visibility won't allow to recover focus
|
||||
|
|
@ -303,12 +305,22 @@
|
|||
(some? modifiers)
|
||||
(gsh/transform-shape modifiers))
|
||||
|
||||
[x y width height]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(let [{:keys [width height]} (wasm.api/get-text-dimensions shape-id)
|
||||
{:keys [x y]} (:selrect shape)]
|
||||
render-wasm? (mf/use-memo #(features/active-feature? @st/state "render-wasm/v1"))
|
||||
|
||||
[x y width height])
|
||||
[{:keys [x y width height]} transform]
|
||||
(if render-wasm?
|
||||
(let [{:keys [width height]} (wasm.api/get-text-dimensions shape-id)
|
||||
selrect-transform (mf/deref refs/workspace-selrect)
|
||||
[selrect transform] (dsh/get-selrect selrect-transform shape)
|
||||
|
||||
valign (-> shape :content :vertical-align)
|
||||
|
||||
y (:y selrect)
|
||||
y (case valign
|
||||
"bottom" (- y (- height (:height selrect)))
|
||||
"center" (- y (/ (- height (:height selrect)) 2))
|
||||
y)]
|
||||
[(assoc selrect :y y :width width :height height) transform])
|
||||
|
||||
(let [bounds (gst/shape->rect shape)
|
||||
x (mth/min (dm/get-prop bounds :x)
|
||||
|
|
@ -319,12 +331,24 @@
|
|||
(dm/get-prop shape :width))
|
||||
height (mth/max (dm/get-prop bounds :height)
|
||||
(dm/get-prop shape :height))]
|
||||
[x y width height]))
|
||||
[(grc/make-rect x y width height) (gsh/transform-matrix shape)]))
|
||||
|
||||
style
|
||||
(cond-> #js {:pointerEvents "all"}
|
||||
render-wasm?
|
||||
(obj/merge!
|
||||
#js {"--editor-container-width" (dm/str width "px")
|
||||
"--editor-container-height" (dm/str height "px")})
|
||||
|
||||
(not (cf/check-browser? :safari))
|
||||
(not render-wasm?)
|
||||
(obj/merge!
|
||||
#js {"--editor-container-width" (dm/str (:width shape) "px")
|
||||
"--editor-container-height" (dm/str (:height shape) "px")})
|
||||
|
||||
;; Transform is necessary when there is a text overflow and the vertical
|
||||
;; aligment is center or bottom.
|
||||
(and (not render-wasm?)
|
||||
(not (cf/check-browser? :safari)))
|
||||
(obj/merge!
|
||||
#js {:transform (dm/fmt "translate(%px, %px)" (- (dm/get-prop shape :x) x) (- (dm/get-prop shape :y) y))})
|
||||
|
||||
|
|
@ -345,7 +369,7 @@
|
|||
(dm/fmt "scale(%)" maybe-zoom))}))]
|
||||
|
||||
[:g.text-editor {:clip-path (dm/fmt "url(#%)" clip-id)
|
||||
:transform (dm/str (gsh/transform-matrix shape))}
|
||||
:transform (dm/str transform)}
|
||||
[:defs
|
||||
[:clipPath {:id clip-id}
|
||||
[:rect {:x x :y y :width width :height height}]]]
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
[app.common.types.component :as ctk]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.refs :as refs]
|
||||
|
|
@ -25,7 +26,6 @@
|
|||
[app.util.debug :as dbg]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.object :as obj]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def rotation-handler-size 20)
|
||||
|
|
@ -327,23 +327,11 @@
|
|||
:style {:fill (if (dbg/enabled? :handlers) "yellow" "none")
|
||||
:stroke-width 0}}]]))
|
||||
|
||||
(def workspace-selrect-transform
|
||||
(l/derived :workspace-selrect st/state))
|
||||
|
||||
(defn get-selrect
|
||||
[selrect-transform shape]
|
||||
(if (some? selrect-transform)
|
||||
(let [{:keys [center width height transform]} selrect-transform]
|
||||
[(gsh/center->rect center width height)
|
||||
(gmt/transform-in center transform)])
|
||||
[(dm/get-prop shape :selrect)
|
||||
(gsh/transform-matrix shape)]))
|
||||
|
||||
(mf/defc controls-selection*
|
||||
[{:keys [shape zoom color on-move-selected on-context-menu disabled]}]
|
||||
(let [selrect-transform (mf/deref workspace-selrect-transform)
|
||||
(let [selrect-transform (mf/deref refs/workspace-selrect)
|
||||
transform-type (mf/deref refs/current-transform)
|
||||
[selrect transform] (get-selrect selrect-transform shape)]
|
||||
[selrect transform] (dsh/get-selrect selrect-transform shape)]
|
||||
|
||||
(when (and (some? selrect)
|
||||
(not (or (= transform-type :move)
|
||||
|
|
@ -360,7 +348,7 @@
|
|||
(mf/defc controls-handlers*
|
||||
{::mf/private true}
|
||||
[{:keys [shape zoom color on-resize on-rotate disabled]}]
|
||||
(let [selrect-transform (mf/deref workspace-selrect-transform)
|
||||
(let [selrect-transform (mf/deref refs/workspace-selrect)
|
||||
transform-type (mf/deref refs/current-transform)
|
||||
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
|
|
@ -368,7 +356,7 @@
|
|||
layout (mf/deref refs/workspace-layout)
|
||||
scale-text? (contains? layout :scale-text)
|
||||
|
||||
[selrect transform] (get-selrect selrect-transform shape)
|
||||
[selrect transform] (dsh/get-selrect selrect-transform shape)
|
||||
|
||||
rotation (-> (gpt/point 1 0)
|
||||
(gpt/transform (:transform shape))
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@
|
|||
(defn apply-modifiers-to-selected
|
||||
[selected objects modifiers]
|
||||
(->> modifiers
|
||||
(filter #(contains? selected (:id %)))
|
||||
(filter #(contains? selected (first %)))
|
||||
(reduce
|
||||
(fn [objects {:keys [id transform]}]
|
||||
(fn [objects [id transform]]
|
||||
(update objects id gsh/apply-transform transform))
|
||||
objects)))
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,13 @@ pub fn identitish(m: &Matrix) -> bool {
|
|||
&& 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)]
|
||||
pub struct Bounds {
|
||||
pub nw: Point,
|
||||
|
|
|
|||
|
|
@ -1472,6 +1472,10 @@ impl RenderState {
|
|||
|
||||
// Z-index ordering on Layouts
|
||||
if element.has_layout() {
|
||||
if element.is_flex() && !element.is_flex_reverse() {
|
||||
children_ids.reverse();
|
||||
}
|
||||
|
||||
children_ids.sort_by(|id1, id2| {
|
||||
let z1 = tree.get(id1).map_or_else(|| 0, |s| s.z_index());
|
||||
let z2 = tree.get(id2).map_or_else(|| 0, |s| s.z_index());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use skia_safe::{self as skia};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use crate::uuid::Uuid;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::{OnceCell, RefCell};
|
||||
|
|
@ -328,6 +330,33 @@ impl Shape {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn is_flex(&self) -> bool {
|
||||
matches!(
|
||||
self.shape_type,
|
||||
Type::Frame(Frame {
|
||||
layout: Some(layouts::Layout::FlexLayout(_, _)),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_flex_reverse(&self) -> bool {
|
||||
matches!(
|
||||
self.shape_type,
|
||||
Type::Frame(Frame {
|
||||
layout: Some(layouts::Layout::FlexLayout(
|
||||
_,
|
||||
FlexData {
|
||||
direction: layouts::FlexDirection::RowReverse
|
||||
| layouts::FlexDirection::ColumnReverse,
|
||||
..
|
||||
}
|
||||
)),
|
||||
..
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_selrect(&mut self, left: f32, top: f32, right: f32, bottom: f32) {
|
||||
self.invalidate_bounds();
|
||||
self.invalidate_extrect();
|
||||
|
|
@ -1257,13 +1286,14 @@ impl Shape {
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
for st in structure {
|
||||
match st.entry_type {
|
||||
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 => {
|
||||
to_remove.insert(&st.id);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ mod flex_layout;
|
|||
pub mod common;
|
||||
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 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::uuid::Uuid;
|
||||
|
|
@ -75,7 +76,7 @@ fn propagate_children(
|
|||
child.ignore_constraints,
|
||||
);
|
||||
|
||||
result.push_back(Modifier::transform(*child_id, transform));
|
||||
result.push_back(Modifier::transform_propagate(*child_id, transform));
|
||||
}
|
||||
|
||||
result
|
||||
|
|
@ -182,33 +183,43 @@ fn propagate_transform(
|
|||
|
||||
let mut transform = entry.transform;
|
||||
|
||||
// NOTA: No puedo utilizar un clone porque entonces estaríamos
|
||||
// perdiendo la referencia al contenido del layout...
|
||||
if let Type::Text(text_content) = &mut shape.shape_type.clone() {
|
||||
if text_content.needs_update_layout() {
|
||||
text_content.update_layout(shape.selrect);
|
||||
}
|
||||
match text_content.grow_type() {
|
||||
GrowType::AutoHeight => {
|
||||
let height = text_content.size.height;
|
||||
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);
|
||||
// Only check the text layout when the width/height changes
|
||||
if !is_close_to(shape_bounds_before.width(), shape_bounds_after.width())
|
||||
|| !is_close_to(shape_bounds_before.height(), shape_bounds_after.height())
|
||||
{
|
||||
if let Type::Text(text_content) = &mut shape.shape_type.clone() {
|
||||
match text_content.grow_type() {
|
||||
GrowType::AutoHeight => {
|
||||
if text_content.needs_update_layout() {
|
||||
text_content.update_layout(shape.selrect);
|
||||
}
|
||||
let height = text_content.size.height;
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -360,7 +378,14 @@ pub fn propagate_modifiers(
|
|||
) -> Vec<TransformEntry> {
|
||||
let mut entries: VecDeque<_> = modifiers
|
||||
.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();
|
||||
|
||||
let mut modifiers = HashMap::<Uuid, Matrix>::new();
|
||||
|
|
@ -407,7 +432,7 @@ pub fn propagate_modifiers(
|
|||
|
||||
modifiers
|
||||
.iter()
|
||||
.map(|(key, val)| TransformEntry::new(*key, *val))
|
||||
.map(|(key, val)| TransformEntry::from_input(*key, *val))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::math::{Bounds, Matrix};
|
||||
use crate::math::{is_move_only_matrix, Bounds, Matrix};
|
||||
use crate::shapes::{ConstraintH, ConstraintV};
|
||||
|
||||
pub fn calculate_resize(
|
||||
|
|
@ -110,7 +110,7 @@ pub fn propagate_shape_constraints(
|
|||
// can propagate as is
|
||||
if (ignore_constrainst
|
||||
|| constraint_h == ConstraintH::Scale && constraint_v == ConstraintV::Scale)
|
||||
|| transform.is_translate()
|
||||
|| is_move_only_matrix(&transform)
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -623,7 +623,7 @@ pub fn reflow_flex_layout(
|
|||
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(
|
||||
layout_data,
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ pub fn reflow_grid_layout(
|
|||
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() {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ pub enum Modifier {
|
|||
}
|
||||
|
||||
impl Modifier {
|
||||
pub fn transform(id: Uuid, transform: Matrix) -> Self {
|
||||
Modifier::Transform(TransformEntry::new(id, transform))
|
||||
pub fn transform_propagate(id: Uuid, transform: Matrix) -> Self {
|
||||
Modifier::Transform(TransformEntry::from_propagate(id, transform))
|
||||
}
|
||||
pub fn parent(id: Uuid, transform: Matrix) -> Self {
|
||||
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)]
|
||||
#[repr(C)]
|
||||
pub struct TransformEntry {
|
||||
pub id: Uuid,
|
||||
pub transform: Matrix,
|
||||
pub source: TransformEntrySource,
|
||||
pub propagate: bool,
|
||||
}
|
||||
|
||||
impl TransformEntry {
|
||||
pub fn new(id: Uuid, transform: Matrix) -> Self {
|
||||
pub fn from_input(id: Uuid, transform: Matrix) -> Self {
|
||||
TransformEntry {
|
||||
id,
|
||||
transform,
|
||||
source: TransformEntrySource::Input,
|
||||
propagate: true,
|
||||
}
|
||||
}
|
||||
pub fn from_propagate(id: Uuid, transform: Matrix) -> Self {
|
||||
TransformEntry {
|
||||
id,
|
||||
transform,
|
||||
source: TransformEntrySource::Propagate,
|
||||
propagate: true,
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +59,7 @@ impl TransformEntry {
|
|||
TransformEntry {
|
||||
id,
|
||||
transform,
|
||||
source: TransformEntrySource::Propagate,
|
||||
propagate: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -70,7 +87,7 @@ impl SerializableResult for TransformEntry {
|
|||
0.0,
|
||||
1.0,
|
||||
);
|
||||
TransformEntry::new(id, transform)
|
||||
TransformEntry::from_input(id, transform)
|
||||
}
|
||||
|
||||
fn as_bytes(&self) -> Self::BytesType {
|
||||
|
|
@ -176,7 +193,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
let entry = TransformEntry::new(
|
||||
let entry = TransformEntry::from_input(
|
||||
Uuid::new_v4(),
|
||||
Matrix::new_all(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.0, 0.0, 1.0),
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue