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:
parent
efc1b87ab0
commit
32756db1c1
3 changed files with 124 additions and 100 deletions
common/src/app/common
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Add table
Reference in a new issue