0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-22 12:41:27 -05:00

Redone the calculus of sizing auto

This commit is contained in:
alonso.torres 2022-11-15 18:17:11 +01:00
parent efc1b87ab0
commit 32756db1c1
3 changed files with 124 additions and 100 deletions
common/src/app/common

View file

@ -135,10 +135,10 @@
(letfn [(apply-modifiers [modif-tree child] (letfn [(apply-modifiers [modif-tree child]
(let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])]
(cond-> child (cond-> child
(some? modifiers) (and (not (cph/group-shape? child)) (some? modifiers))
(gtr/transform-shape modifiers) (gtr/transform-shape modifiers)
(cph/group-like-shape? child) (cph/group-shape? child)
(gtr/apply-group-modifiers objects modif-tree)))) (gtr/apply-group-modifiers objects modif-tree))))
(set-child-modifiers [parent [layout-line modif-tree] child] (set-child-modifiers [parent [layout-line modif-tree] child]
@ -152,7 +152,7 @@
[layout-line modif-tree]))] [layout-line modif-tree]))]
(let [children (map (d/getf objects) (:shapes parent)) (let [children (map (d/getf objects) (:shapes parent))
children (->> children (map (partial apply-modifiers modif-tree))) children (->> children (map (partial apply-modifiers modif-tree)))
layout-data (gcl/calc-layout-data parent children) layout-data (gcl/calc-layout-data parent children)
children (into [] (cond-> children (:reverse? layout-data) reverse)) children (into [] (cond-> children (:reverse? layout-data) reverse))
@ -173,119 +173,136 @@
modif-tree))))) modif-tree)))))
(defn- set-auto-modifiers (defn- calc-auto-modifiers
"Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes" "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes"
[modif-tree objects parent] [objects parent]
(letfn [(apply-modifiers (letfn [(set-parent-auto-width
[child] [modifiers auto-width]
(let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])]
(cond-> child
(some? modifiers)
(gtr/transform-shape modifiers)
(and (some? modifiers) (cph/group-like-shape? child))
(gtr/apply-group-modifiers objects modif-tree))))
(set-parent-auto-width
[modifiers parent auto-width]
(let [origin (-> parent :points first) (let [origin (-> parent :points first)
scale-width (/ auto-width (-> parent :selrect :width) )] scale-width (/ auto-width (-> parent :selrect :width) )]
(-> modifiers (-> modifiers
(ctm/resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent))))) (ctm/resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
(set-parent-auto-height (set-parent-auto-height
[modifiers parent auto-height] [modifiers auto-height]
(let [origin (-> parent :points first) (let [origin (-> parent :points first)
scale-height (/ auto-height (-> parent :selrect :height) )] scale-height (/ auto-height (-> parent :selrect :height) )]
(-> modifiers (-> modifiers
(ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))] (ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))]
(let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) (let [children (->> parent :shapes (map (d/getf objects)))
children (->> parent
:shapes
(map (comp apply-modifiers (d/getf objects))))
{auto-width :width auto-height :height} {auto-width :width auto-height :height}
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent))) (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
(gcl/layout-content-bounds parent children)) (gcl/layout-content-bounds parent children))]
modifiers (cond-> (ctm/empty)
(cond-> modifiers (and (some? auto-width) (ctl/auto-width? parent))
(and (some? auto-width) (ctl/auto-width? parent)) (set-parent-auto-width auto-width)
(set-parent-auto-width parent auto-width)
(and (some? auto-height) (ctl/auto-height? parent)) (and (some? auto-height) (ctl/auto-height? parent))
(set-parent-auto-height parent auto-height))] (set-parent-auto-height auto-height)))))
(assoc-in modif-tree [(:id parent) :modifiers] modifiers))))
(defn- propagate-modifiers (defn- propagate-modifiers
"Propagate modifiers to its children" "Propagate modifiers to its children"
[objects ignore-constraints [modif-tree recalculate] parent] [objects ignore-constraints [modif-tree autolayouts] parent]
(let [parent-id (:id parent) (let [parent-id (:id parent)
root? (= uuid/zero parent-id) root? (= uuid/zero parent-id)
modifiers (dm/get-in modif-tree [parent-id :modifiers]) modifiers (dm/get-in modif-tree [parent-id :modifiers])
transformed-parent (gtr/transform-shape parent modifiers) transformed-parent (gtr/transform-shape parent modifiers)
has-modifiers? (ctm/child-modifiers? modifiers) has-modifiers? (ctm/child-modifiers? modifiers)
is-layout? (ctl/layout? parent) layout? (ctl/layout? parent)
is-auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent))
is-parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
;; If the current child is inside the layout we ignore the constraints ;; If the current child is inside the layout we ignore the constraints
is-inside-layout? (ctl/inside-layout? objects parent)] inside-layout? (ctl/inside-layout? objects parent)]
[(cond-> modif-tree [(cond-> modif-tree
(and (not is-layout?) has-modifiers? is-parent? (not root?)) (and (not layout?) has-modifiers? parent? (not root?))
(set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?)) (set-children-modifiers objects parent transformed-parent (or ignore-constraints inside-layout?))
is-layout? layout?
(-> (process-layout-children objects parent transformed-parent) (-> (process-layout-children objects parent transformed-parent)
(set-layout-modifiers objects transformed-parent)) (set-layout-modifiers objects transformed-parent)))
is-auto? ;; Auto-width/height can change the positions in the parent so we need to recalculate
(set-auto-modifiers objects transformed-parent)) (cond-> autolayouts auto? (conj (:id parent)))]))
(cond-> recalculate (defn- apply-structure-modifiers
;; Auto-width/height can change the positions in the parent so we need to recalculate [objects modif-tree]
is-auto? (letfn [(apply-shape [objects [id {:keys [modifiers]}]]
(conj (:id parent)))])) (if (ctm/has-structure? modifiers)
(let [shape (get objects id)]
(update objects id ctm/apply-structure-modifiers modifiers))
objects))]
(reduce apply-shape objects modif-tree)))
(defn- calculate-reflow-layout (defn- apply-partial-objects-modifiers
[objects modif-tree parent] [objects tree-seq modif-tree]
(let [is-layout? (ctl/layout? parent)
is-auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
modifiers (dm/get-in modif-tree [(:id parent) :modifiers])
transformed-parent (gtr/transform-shape parent modifiers)]
(cond-> modif-tree
is-layout?
(set-layout-modifiers objects transformed-parent)
is-auto? (letfn [(apply-shape [objects {:keys [id] :as shape}]
(set-auto-modifiers objects transformed-parent)))) (if (cph/group-shape? shape)
(let [children (cph/get-children objects id)]
(assoc objects id
(cond
(cph/mask-shape? shape)
(gtr/update-mask-selrect shape children)
:else
(gtr/update-group-selrect shape children))))
(let [modifiers (get-in modif-tree [id :modifiers])
object (cond-> shape
(some? modifiers)
(gtr/transform-shape modifiers))]
(assoc objects id object))))]
(reduce apply-shape objects (reverse tree-seq))))
(defn merge-modif-tree
[modif-tree other-tree]
(reduce (fn [modif-tree [id {:keys [modifiers]}]]
(update-in modif-tree [id :modifiers] ctm/add-modifiers modifiers))
modif-tree
other-tree))
(defn sizing-auto-modifiers
"Recalculates the layouts to adjust the sizing: auto new sizes"
[modif-tree sizing-auto-layouts objects ignore-constraints]
(loop [modif-tree modif-tree
sizing-auto-layouts (reverse sizing-auto-layouts)]
(if-let [current (first sizing-auto-layouts)]
(let [parent-base (get objects current)
tree-seq (resolve-tree-sequence #{current} objects)
;; Apply the current stack of transformations so we can calculate the auto-layouts
objects (apply-partial-objects-modifiers objects tree-seq modif-tree)
resize-modif-tree
{current {:modifiers (calc-auto-modifiers objects parent-base)}}
tree-seq (resolve-tree-sequence #{current} objects)
[resize-modif-tree _]
(reduce (partial propagate-modifiers objects ignore-constraints) [resize-modif-tree #{}] tree-seq)
modif-tree (merge-modif-tree modif-tree resize-modif-tree)]
(recur modif-tree (rest sizing-auto-layouts)))
modif-tree)))
(defn set-objects-modifiers (defn set-objects-modifiers
[modif-tree objects ignore-constraints snap-pixel?] [modif-tree objects ignore-constraints snap-pixel?]
(let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) (let [objects (apply-structure-modifiers objects modif-tree)
shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects)
[modif-tree recalculate] [modif-tree sizing-auto-layouts]
(reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree) (reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree)
shapes-tree (resolve-tree-sequence recalculate objects) ;; Calculate hug layouts positions
modif-tree (sizing-auto-modifiers modif-tree sizing-auto-layouts objects ignore-constraints)
;; We need to go again and recalculate the layout positions+hug
;; TODO LAYOUT: How to remove this recalculation?
modif-tree
(->> shapes-tree
reverse
(filter ctl/layout?)
(reduce (partial calculate-reflow-layout objects) modif-tree))
modif-tree
(->> shapes-tree
(filter ctl/layout?)
(reduce (partial calculate-reflow-layout objects) modif-tree))
modif-tree modif-tree
(cond-> modif-tree (cond-> modif-tree

View file

@ -369,6 +369,9 @@
;; Points for every shape inside the group ;; Points for every shape inside the group
points (->> children (mapcat :points)) points (->> children (mapcat :points))
;; Fixed problem with empty groups. Should not happen (but it does)
points (if (empty? points) (:points group) points)
;; Invert to get the points minus the transforms applied to the group ;; Invert to get the points minus the transforms applied to the group
base-points (gco/transform-points points shape-center (:transform-inverse group (gmt/matrix))) base-points (gco/transform-points points shape-center (:transform-inverse group (gmt/matrix)))
@ -478,43 +481,43 @@
(declare apply-group-modifiers) (declare apply-group-modifiers)
(defn apply-children-modifiers (defn apply-children-modifiers
[objects modif-tree parent-modifiers children] [objects modif-tree parent-modifiers children propagate?]
(->> children (->> children
(map (fn [child] (map (fn [child]
(let [modifiers (->> (get-in modif-tree [(:id child) :modifiers]) (let [modifiers (cond-> (get-in modif-tree [(:id child) :modifiers])
(ctm/add-modifiers parent-modifiers)) propagate? (ctm/add-modifiers parent-modifiers))
child (transform-shape child modifiers) child (transform-shape child modifiers)
parent? (cph/group-like-shape? child)] parent? (cph/group-like-shape? child)
modif-tree
(cond-> modif-tree
propagate?
(assoc-in [(:id child) :modifiers] modifiers))]
(cond-> child (cond-> child
parent? parent?
(apply-group-modifiers objects (assoc-in modif-tree [(:id child) :modifiers] modifiers)))))))) (apply-group-modifiers objects modif-tree propagate?)))))))
(defn apply-group-modifiers (defn apply-group-modifiers
"Apply the modifiers to the group children to calculate its selection rect" "Apply the modifiers to the group children to calculate its selection rect"
[group objects modif-tree] ([group objects modif-tree]
(apply-group-modifiers group objects modif-tree true))
(let [modifiers (get-in modif-tree [(:id group) :modifiers]) ([group objects modif-tree propagate?]
children (->> (:shapes group) (let [modifiers (get-in modif-tree [(:id group) :modifiers])
(map (d/getf objects)) children
(apply-children-modifiers objects modif-tree modifiers))] (as-> (:shapes group) $
(cond (map (d/getf objects) $)
(cph/mask-shape? group) (apply-children-modifiers objects modif-tree modifiers $ propagate?))]
(update-mask-selrect group children) (cond
(cph/mask-shape? group)
(update-mask-selrect group children)
(cph/group-shape? group) (cph/group-shape? group)
(update-group-selrect group children) (update-group-selrect group children)
:else :else
group))) group))))
(defn get-children-bounds
[parent objects modif-tree]
(let [modifiers (get-in modif-tree [(:id parent) :modifiers])
children
(->> (:shapes parent)
(map (d/getf objects))
(apply-children-modifiers objects modif-tree modifiers))]
(->> children (mapcat :points) gpr/points->rect)))
(defn parent-coords-rect (defn parent-coords-rect
[child parent] [child parent]

View file

@ -384,7 +384,11 @@
(defn select-structure (defn select-structure
[modifiers] [modifiers]
(select-keys modifiers [:structure-parent])) (select-keys modifiers [:structure-parent :structure-child]))
(defn select-geometry
[modifiers]
(select-keys modifiers [:geometry-parent :geometry-child]))
(defn added-children-frames (defn added-children-frames
"Returns the frames that have an 'add-children' operation" "Returns the frames that have an 'add-children' operation"