mirror of
https://github.com/penpot/penpot.git
synced 2025-02-15 19:48:22 -05:00
✨ Viewport and hug performance enhances
This commit is contained in:
parent
399d57ace0
commit
f579bb0c8d
16 changed files with 270 additions and 199 deletions
|
@ -688,3 +688,12 @@
|
||||||
(if (contains? set value)
|
(if (contains? set value)
|
||||||
(disj set value)
|
(disj set value)
|
||||||
(conj set value)))))
|
(conj set value)))))
|
||||||
|
|
||||||
|
(defn lazy-map
|
||||||
|
"Creates a map with lazy values given the generator function that receives as argument
|
||||||
|
the key for the value to be generated"
|
||||||
|
[keys generator-fn]
|
||||||
|
(into {}
|
||||||
|
(map (fn [key]
|
||||||
|
[key (delay (generator-fn key))]))
|
||||||
|
keys))
|
||||||
|
|
|
@ -252,6 +252,10 @@
|
||||||
(let [v-length (length v)]
|
(let [v-length (length v)]
|
||||||
(divide v (point v-length v-length))))
|
(divide v (point v-length v-length))))
|
||||||
|
|
||||||
|
(defn perpendicular
|
||||||
|
[{:keys [x y]}]
|
||||||
|
(Point. (- y) x))
|
||||||
|
|
||||||
(defn project
|
(defn project
|
||||||
"V1 perpendicular projection on vector V2"
|
"V1 perpendicular projection on vector V2"
|
||||||
[v1 v2]
|
[v1 v2]
|
||||||
|
|
|
@ -251,9 +251,11 @@
|
||||||
|
|
||||||
(defn normalize-modifiers
|
(defn normalize-modifiers
|
||||||
"Before aplying constraints we need to remove the deformation caused by the resizing of the parent"
|
"Before aplying constraints we need to remove the deformation caused by the resizing of the parent"
|
||||||
[constraints-h constraints-v modifiers child {:keys [transform transform-inverse] :as parent} transformed-child-bounds transformed-parent-bounds]
|
[constraints-h constraints-v modifiers
|
||||||
|
{:keys [transform transform-inverse] :as parent}
|
||||||
|
child-bounds transformed-child-bounds parent-bounds transformed-parent-bounds]
|
||||||
|
|
||||||
(let [child-bb-before (gpo/parent-coords-bounds (:points child) (:points parent))
|
(let [child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||||
child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
|
child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
|
||||||
|
|
||||||
scale-x (if (= :scale constraints-h)
|
scale-x (if (= :scale constraints-h)
|
||||||
|
@ -278,7 +280,7 @@
|
||||||
resize-transform-inverse))))
|
resize-transform-inverse))))
|
||||||
|
|
||||||
(defn calc-child-modifiers
|
(defn calc-child-modifiers
|
||||||
[parent child modifiers ignore-constraints parent-bounds transformed-parent-bounds]
|
[parent child modifiers ignore-constraints child-bounds parent-bounds transformed-parent-bounds]
|
||||||
|
|
||||||
(let [modifiers (ctm/select-child-modifiers modifiers)
|
(let [modifiers (ctm/select-child-modifiers modifiers)
|
||||||
|
|
||||||
|
@ -295,10 +297,13 @@
|
||||||
(if (and (= :scale constraints-h) (= :scale constraints-v))
|
(if (and (= :scale constraints-h) (= :scale constraints-v))
|
||||||
modifiers
|
modifiers
|
||||||
|
|
||||||
(let [child-bounds (:points child)
|
(let [transformed-parent-bounds @transformed-parent-bounds
|
||||||
|
|
||||||
modifiers (ctm/select-child-modifiers modifiers)
|
modifiers (ctm/select-child-modifiers modifiers)
|
||||||
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
||||||
modifiers (normalize-modifiers constraints-h constraints-v modifiers child parent transformed-child-bounds transformed-parent-bounds)
|
modifiers (normalize-modifiers constraints-h constraints-v
|
||||||
|
modifiers parent
|
||||||
|
child-bounds transformed-child-bounds parent-bounds transformed-parent-bounds)
|
||||||
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
||||||
|
|
||||||
child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||||
|
|
|
@ -7,21 +7,19 @@
|
||||||
(ns app.common.geom.shapes.flex-layout.bounds
|
(ns app.common.geom.shapes.flex-layout.bounds
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.common :as gco]
|
|
||||||
[app.common.geom.shapes.points :as gpo]
|
[app.common.geom.shapes.points :as gpo]
|
||||||
[app.common.geom.shapes.rect :as gre]
|
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.types.shape.layout :as ctl]))
|
[app.common.types.shape.layout :as ctl]))
|
||||||
|
|
||||||
(defn- child-layout-bound-points
|
(defn- child-layout-bound-points
|
||||||
"Returns the bounds of the children as points"
|
"Returns the bounds of the children as points"
|
||||||
[parent child]
|
[parent child parent-bounds child-bounds]
|
||||||
|
|
||||||
(let [row? (ctl/row? parent)
|
(let [row? (ctl/row? parent)
|
||||||
col? (ctl/col? parent)
|
col? (ctl/col? parent)
|
||||||
|
|
||||||
hv (partial gpo/start-hv (:points parent))
|
hv (partial gpo/start-hv parent-bounds)
|
||||||
vv (partial gpo/start-vv (:points parent))
|
vv (partial gpo/start-vv parent-bounds)
|
||||||
|
|
||||||
v-start? (ctl/v-start? parent)
|
v-start? (ctl/v-start? parent)
|
||||||
v-center? (ctl/v-center? parent)
|
v-center? (ctl/v-center? parent)
|
||||||
|
@ -30,10 +28,10 @@
|
||||||
h-center? (ctl/h-center? parent)
|
h-center? (ctl/h-center? parent)
|
||||||
h-end? (ctl/h-end? parent)
|
h-end? (ctl/h-end? parent)
|
||||||
|
|
||||||
base-p (first (:points child))
|
base-p (gpo/origin child-bounds)
|
||||||
|
|
||||||
width (-> child :selrect :width)
|
width (gpo/width-points child-bounds)
|
||||||
height (-> child :selrect :height)
|
height (gpo/height-points child-bounds)
|
||||||
|
|
||||||
min-width (if (ctl/fill-width? child)
|
min-width (if (ctl/fill-width? child)
|
||||||
(ctl/child-min-width child)
|
(ctl/child-min-width child)
|
||||||
|
@ -91,22 +89,29 @@
|
||||||
(gpt/subtract (vv min-height)))))))
|
(gpt/subtract (vv min-height)))))))
|
||||||
|
|
||||||
(defn layout-content-bounds
|
(defn layout-content-bounds
|
||||||
[{:keys [layout-padding] :as parent} children]
|
[bounds {:keys [layout-padding] :as parent} children]
|
||||||
|
|
||||||
(let [{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding
|
(let [parent-id (:id parent)
|
||||||
|
parent-bounds @(get bounds parent-id)
|
||||||
|
|
||||||
|
{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding
|
||||||
pad-top (or pad-top 0)
|
pad-top (or pad-top 0)
|
||||||
pad-right (or pad-right 0)
|
pad-right (or pad-right 0)
|
||||||
pad-bottom (or pad-bottom 0)
|
pad-bottom (or pad-bottom 0)
|
||||||
pad-left (or pad-left 0)
|
pad-left (or pad-left 0)
|
||||||
|
|
||||||
child-bounds
|
child-bounds
|
||||||
(fn [{:keys [points] :as child}]
|
(fn [child]
|
||||||
|
(let [child-id (:id child)
|
||||||
|
child-bounds @(get bounds child-id)
|
||||||
|
child-bounds
|
||||||
(if (or (ctl/fill-height? child) (ctl/fill-height? child))
|
(if (or (ctl/fill-height? child) (ctl/fill-height? child))
|
||||||
(child-layout-bound-points parent child)
|
(child-layout-bound-points parent child parent-bounds parent-bounds)
|
||||||
points))]
|
child-bounds)]
|
||||||
|
(gpo/parent-coords-bounds child-bounds parent-bounds)))]
|
||||||
|
|
||||||
|
(as-> children $
|
||||||
|
(map child-bounds $)
|
||||||
|
(gpo/merge-parent-coords-bounds $ parent-bounds)
|
||||||
|
(gpo/pad-points $ (- pad-top) (- pad-right) (- pad-bottom) (- pad-left)))))
|
||||||
|
|
||||||
(-> (mapcat child-bounds children)
|
|
||||||
(gco/transform-points (gco/center-shape parent) (:transform-inverse parent))
|
|
||||||
(gre/squared-points)
|
|
||||||
(gpo/pad-points (- pad-top) (- pad-right) (- pad-bottom) (- pad-left))
|
|
||||||
(gre/points->rect))))
|
|
||||||
|
|
|
@ -16,12 +16,9 @@
|
||||||
|
|
||||||
(defn normalize-child-modifiers
|
(defn normalize-child-modifiers
|
||||||
"Apply the modifiers and then normalized them against the parent coordinates"
|
"Apply the modifiers and then normalized them against the parent coordinates"
|
||||||
[modifiers {:keys [transform transform-inverse] :as parent} child transformed-parent-bounds]
|
[modifiers {:keys [transform transform-inverse] :as parent} child-bounds parent-bounds transformed-parent-bounds]
|
||||||
|
|
||||||
(let [child-bounds (:points child)
|
(let [transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
||||||
parent-bounds (:points parent)
|
|
||||||
|
|
||||||
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
|
||||||
|
|
||||||
child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
child-bb-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||||
child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
|
child-bb-after (gpo/parent-coords-bounds transformed-child-bounds transformed-parent-bounds)
|
||||||
|
@ -30,7 +27,7 @@
|
||||||
scale-y (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after))
|
scale-y (/ (gpo/height-points child-bb-before) (gpo/height-points child-bb-after))
|
||||||
|
|
||||||
resize-vector (gpt/point scale-x scale-y)
|
resize-vector (gpt/point scale-x scale-y)
|
||||||
modif-transform (ctm/modifiers->transform modifiers)
|
modif-transform (or (ctm/modifiers->transform modifiers) (gmt/matrix))
|
||||||
modif-transform-inverse (gmt/inverse modif-transform)
|
modif-transform-inverse (gmt/inverse modif-transform)
|
||||||
resize-transform (gmt/multiply modif-transform transform)
|
resize-transform (gmt/multiply modif-transform transform)
|
||||||
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
|
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
|
|
||||||
(defn- set-children-modifiers
|
(defn- set-children-modifiers
|
||||||
"Propagates the modifiers from a parent too its children applying constraints if necesary"
|
"Propagates the modifiers from a parent too its children applying constraints if necesary"
|
||||||
[modif-tree objects parent transformed-parent-bounds ignore-constraints]
|
[modif-tree objects bounds parent transformed-parent-bounds ignore-constraints]
|
||||||
(let [children (:shapes parent)
|
(let [children (:shapes parent)
|
||||||
modifiers (dm/get-in modif-tree [(:id parent) :modifiers])]
|
modifiers (dm/get-in modif-tree [(:id parent) :modifiers])]
|
||||||
|
|
||||||
|
@ -106,59 +106,67 @@
|
||||||
modif-tree))
|
modif-tree))
|
||||||
|
|
||||||
;; Check the constraints, then resize
|
;; Check the constraints, then resize
|
||||||
(let [parent-bounds (gtr/transform-bounds (:points parent) (ctm/select-parent-modifiers modifiers))]
|
(let [parent-id (:id parent)
|
||||||
|
parent-bounds (gtr/transform-bounds @(get bounds parent-id) (ctm/select-parent-modifiers modifiers))]
|
||||||
(loop [modif-tree modif-tree
|
(loop [modif-tree modif-tree
|
||||||
children (seq children)]
|
children (seq children)]
|
||||||
(if (empty? children)
|
(if (empty? children)
|
||||||
modif-tree
|
modif-tree
|
||||||
(let [child-id (first children)
|
(let [child-id (first children)
|
||||||
child (get objects child-id)
|
child (get objects child-id)
|
||||||
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints parent-bounds @transformed-parent-bounds)]
|
child-bounds @(get bounds child-id)
|
||||||
|
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints child-bounds parent-bounds transformed-parent-bounds)]
|
||||||
(recur (cond-> modif-tree
|
(recur (cond-> modif-tree
|
||||||
(not (ctm/empty? child-modifiers))
|
(not (ctm/empty? child-modifiers))
|
||||||
(update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))
|
(update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))
|
||||||
(rest children)))))))))
|
(rest children)))))))))
|
||||||
|
|
||||||
(defn- process-layout-children
|
(defn- process-layout-children
|
||||||
[modif-tree objects parent transformed-parent-bounds]
|
[modif-tree objects bounds parent transformed-parent-bounds]
|
||||||
(letfn [(process-child [modif-tree child]
|
(letfn [(process-child [modif-tree child]
|
||||||
(let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers])
|
(let [child-id (:id child)
|
||||||
|
parent-id (:id parent)
|
||||||
|
modifiers (dm/get-in modif-tree [parent-id :modifiers])
|
||||||
|
child-bounds @(get bounds child-id)
|
||||||
|
parent-bounds @(get bounds parent-id)
|
||||||
child-modifiers (-> modifiers
|
child-modifiers (-> modifiers
|
||||||
(ctm/select-child-geometry-modifiers)
|
(ctm/select-child-geometry-modifiers)
|
||||||
(gcl/normalize-child-modifiers parent child @transformed-parent-bounds))]
|
(gcl/normalize-child-modifiers parent child-bounds parent-bounds @transformed-parent-bounds))]
|
||||||
(cond-> modif-tree
|
(cond-> modif-tree
|
||||||
(not (ctm/empty? child-modifiers))
|
(not (ctm/empty? child-modifiers))
|
||||||
(update-in [(:id child) :modifiers] ctm/add-modifiers child-modifiers))))]
|
(update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))))]
|
||||||
(let [children (map (d/getf objects) (:shapes parent))]
|
(let [children (map (d/getf objects) (:shapes parent))]
|
||||||
(reduce process-child modif-tree children))))
|
(reduce process-child modif-tree children))))
|
||||||
|
|
||||||
|
|
||||||
(defn get-bounds
|
(defn get-group-bounds
|
||||||
[objects modif-tree shape]
|
[objects bounds modif-tree shape]
|
||||||
|
(let [shape-id (:id shape)
|
||||||
(let [modifiers (-> (dm/get-in modif-tree [(:id shape) :modifiers])
|
modifiers (-> (dm/get-in modif-tree [shape-id :modifiers])
|
||||||
(ctm/select-geometry))
|
(ctm/select-geometry))
|
||||||
|
|
||||||
children (cph/get-immediate-children objects (:id shape))
|
children (cph/get-immediate-children objects shape-id)
|
||||||
bounds (cond
|
group-bounds
|
||||||
|
(cond
|
||||||
(cph/group-shape? shape)
|
(cph/group-shape? shape)
|
||||||
(let [children-bounds (->> children (mapv (partial get-bounds objects modif-tree)))]
|
(let [children-bounds (->> children (mapv #(get-group-bounds objects bounds modif-tree %)))]
|
||||||
(gtr/group-bounds shape children-bounds))
|
(gtr/group-bounds shape children-bounds))
|
||||||
|
|
||||||
(cph/mask-shape? shape)
|
(cph/mask-shape? shape)
|
||||||
(get-bounds objects modif-tree (-> children first))
|
(get-group-bounds objects bounds modif-tree (-> children first))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(:points shape))]
|
@(get bounds shape-id))]
|
||||||
|
|
||||||
(gtr/transform-bounds bounds modifiers)))
|
|
||||||
|
|
||||||
|
(cond-> group-bounds
|
||||||
|
(not (ctm/empty? modifiers))
|
||||||
|
(gtr/transform-bounds modifiers))))
|
||||||
|
|
||||||
(defn- set-layout-modifiers
|
(defn- set-layout-modifiers
|
||||||
[modif-tree objects parent transformed-parent-bounds]
|
[modif-tree objects bounds parent transformed-parent-bounds]
|
||||||
|
|
||||||
(letfn [(apply-modifiers [child]
|
(letfn [(apply-modifiers [child]
|
||||||
[(-> (get-bounds objects modif-tree child)
|
[(-> (get-group-bounds objects bounds modif-tree child)
|
||||||
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
||||||
child])
|
child])
|
||||||
|
|
||||||
|
@ -195,57 +203,63 @@
|
||||||
|
|
||||||
(defn- calc-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"
|
||||||
[objects parent]
|
[objects bounds parent]
|
||||||
(letfn [(set-parent-auto-width
|
(let [parent-id (:id parent)
|
||||||
[modifiers auto-width]
|
parent-bounds (get bounds parent-id)
|
||||||
(let [origin (-> parent :points first)
|
|
||||||
scale-width (/ auto-width (-> parent :selrect :width) )]
|
set-parent-auto-width
|
||||||
|
(fn [modifiers auto-width]
|
||||||
|
(let [origin (gpo/origin @parent-bounds)
|
||||||
|
scale-width (/ auto-width (gpo/width-points @parent-bounds))]
|
||||||
(-> 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 auto-height]
|
(fn [modifiers auto-height]
|
||||||
(let [origin (-> parent :points first)
|
(let [origin (gpo/origin @parent-bounds)
|
||||||
scale-height (/ auto-height (-> parent :selrect :height) )]
|
scale-height (/ auto-height (gpo/height-points @parent-bounds))]
|
||||||
(-> 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 [children (->> parent :shapes (map (d/getf objects)))
|
children (->> parent :shapes (map (d/getf objects)))
|
||||||
{auto-width :width auto-height :height}
|
content-bounds
|
||||||
(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 bounds parent children))
|
||||||
|
|
||||||
|
auto-width (when content-bounds (gpo/width-points content-bounds))
|
||||||
|
auto-height (when content-bounds (gpo/height-points content-bounds))]
|
||||||
|
|
||||||
(cond-> (ctm/empty)
|
(cond-> (ctm/empty)
|
||||||
(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 auto-width)
|
||||||
|
|
||||||
(and (some? auto-height) (ctl/auto-height? parent))
|
(and (some? auto-height) (ctl/auto-height? parent))
|
||||||
(set-parent-auto-height auto-height)))))
|
(set-parent-auto-height auto-height))))
|
||||||
|
|
||||||
(defn- propagate-modifiers
|
(defn- propagate-modifiers
|
||||||
"Propagate modifiers to its children"
|
"Propagate modifiers to its children"
|
||||||
[objects ignore-constraints [modif-tree autolayouts] parent]
|
[objects bounds 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])
|
||||||
(ctm/select-geometry))
|
(ctm/select-geometry))
|
||||||
|
|
||||||
transformed-parent-bounds (delay (gtr/transform-bounds (:points parent) modifiers))
|
|
||||||
|
|
||||||
has-modifiers? (ctm/child-modifiers? modifiers)
|
has-modifiers? (ctm/child-modifiers? modifiers)
|
||||||
layout? (ctl/layout? parent)
|
layout? (ctl/layout? parent)
|
||||||
auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
|
auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
|
||||||
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
|
||||||
inside-layout? (ctl/inside-layout? objects parent)]
|
inside-layout? (ctl/inside-layout? objects parent)
|
||||||
|
|
||||||
|
transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))]
|
||||||
|
|
||||||
[(cond-> modif-tree
|
[(cond-> modif-tree
|
||||||
(and (not layout?) has-modifiers? parent? (not root?))
|
(and (not layout?) has-modifiers? parent? (not root?))
|
||||||
(set-children-modifiers objects parent transformed-parent-bounds (or ignore-constraints inside-layout?))
|
(set-children-modifiers objects bounds parent transformed-parent-bounds (or ignore-constraints inside-layout?))
|
||||||
|
|
||||||
layout?
|
layout?
|
||||||
(-> (process-layout-children objects parent transformed-parent-bounds)
|
(-> (process-layout-children objects bounds parent transformed-parent-bounds)
|
||||||
(set-layout-modifiers objects parent transformed-parent-bounds)))
|
(set-layout-modifiers objects bounds parent transformed-parent-bounds)))
|
||||||
|
|
||||||
;; Auto-width/height can change the positions in the parent so we need to recalculate
|
;; Auto-width/height can change the positions in the parent so we need to recalculate
|
||||||
(cond-> autolayouts auto? (conj (:id parent)))]))
|
(cond-> autolayouts auto? (conj (:id parent)))]))
|
||||||
|
@ -258,28 +272,6 @@
|
||||||
(update id ctm/apply-structure-modifiers modifiers)))]
|
(update id ctm/apply-structure-modifiers modifiers)))]
|
||||||
(reduce apply-shape objects modif-tree)))
|
(reduce apply-shape objects modif-tree)))
|
||||||
|
|
||||||
(defn- apply-partial-objects-modifiers
|
|
||||||
[objects tree-seq modif-tree]
|
|
||||||
|
|
||||||
(letfn [(apply-shape [objects {:keys [id] :as shape}]
|
|
||||||
(let [modifiers (get-in modif-tree [id :modifiers])
|
|
||||||
object
|
|
||||||
(cond
|
|
||||||
(cph/mask-shape? shape)
|
|
||||||
(gtr/update-mask-selrect shape (cph/get-children objects id))
|
|
||||||
|
|
||||||
(cph/group-shape? shape)
|
|
||||||
(gtr/update-group-selrect shape (cph/get-children objects id))
|
|
||||||
|
|
||||||
(some? modifiers)
|
|
||||||
(gtr/transform-shape shape modifiers)
|
|
||||||
|
|
||||||
:else
|
|
||||||
shape)]
|
|
||||||
(assoc objects id object)))]
|
|
||||||
|
|
||||||
(reduce apply-shape objects (reverse tree-seq))))
|
|
||||||
|
|
||||||
(defn merge-modif-tree
|
(defn merge-modif-tree
|
||||||
[modif-tree other-tree]
|
[modif-tree other-tree]
|
||||||
(reduce (fn [modif-tree [id {:keys [modifiers]}]]
|
(reduce (fn [modif-tree [id {:keys [modifiers]}]]
|
||||||
|
@ -287,41 +279,58 @@
|
||||||
modif-tree
|
modif-tree
|
||||||
other-tree))
|
other-tree))
|
||||||
|
|
||||||
|
(defn transform-bounds
|
||||||
|
[bounds objects modif-tree]
|
||||||
|
|
||||||
|
(loop [result bounds
|
||||||
|
ids (keys modif-tree)]
|
||||||
|
(if (empty? ids)
|
||||||
|
result
|
||||||
|
|
||||||
|
(let [id (first ids)
|
||||||
|
shape (get objects id)
|
||||||
|
new-bounds (delay (get-group-bounds objects bounds modif-tree shape))
|
||||||
|
result (assoc result id new-bounds)]
|
||||||
|
(recur result (rest ids))))))
|
||||||
|
|
||||||
(defn sizing-auto-modifiers
|
(defn sizing-auto-modifiers
|
||||||
"Recalculates the layouts to adjust the sizing: auto new sizes"
|
"Recalculates the layouts to adjust the sizing: auto new sizes"
|
||||||
[modif-tree sizing-auto-layouts objects ignore-constraints]
|
[modif-tree sizing-auto-layouts objects bounds ignore-constraints]
|
||||||
(loop [modif-tree modif-tree
|
(loop [modif-tree modif-tree
|
||||||
|
bounds (transform-bounds bounds objects modif-tree)
|
||||||
sizing-auto-layouts (reverse sizing-auto-layouts)]
|
sizing-auto-layouts (reverse sizing-auto-layouts)]
|
||||||
(if-let [current (first sizing-auto-layouts)]
|
(if-let [current (first sizing-auto-layouts)]
|
||||||
(let [parent-base (get objects current)
|
(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
|
resize-modif-tree
|
||||||
{current {:modifiers (calc-auto-modifiers objects parent-base)}}
|
{current {:modifiers (calc-auto-modifiers objects bounds parent-base)}}
|
||||||
|
|
||||||
tree-seq (resolve-tree-sequence #{current} objects)
|
tree-seq (resolve-tree-sequence #{current} objects)
|
||||||
|
|
||||||
[resize-modif-tree _]
|
[resize-modif-tree _]
|
||||||
(reduce (partial propagate-modifiers objects ignore-constraints) [resize-modif-tree #{}] tree-seq)
|
(reduce #(propagate-modifiers objects bounds ignore-constraints %1 %2) [resize-modif-tree #{}] tree-seq)
|
||||||
|
|
||||||
|
bounds (transform-bounds bounds objects resize-modif-tree)
|
||||||
|
|
||||||
modif-tree (merge-modif-tree modif-tree resize-modif-tree)]
|
modif-tree (merge-modif-tree modif-tree resize-modif-tree)]
|
||||||
(recur modif-tree (rest sizing-auto-layouts)))
|
(recur modif-tree bounds (rest sizing-auto-layouts)))
|
||||||
modif-tree)))
|
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 [objects (apply-structure-modifiers objects modif-tree)
|
(let [objects (apply-structure-modifiers objects modif-tree)
|
||||||
|
bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points]))
|
||||||
|
|
||||||
shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects)
|
shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects)
|
||||||
|
|
||||||
[modif-tree sizing-auto-layouts]
|
[modif-tree sizing-auto-layouts]
|
||||||
(reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree)
|
(reduce #(propagate-modifiers objects bounds ignore-constraints %1 %2) [modif-tree #{}] shapes-tree)
|
||||||
|
|
||||||
;; Calculate hug layouts positions
|
;; Calculate hug layouts positions
|
||||||
modif-tree (sizing-auto-modifiers modif-tree sizing-auto-layouts objects ignore-constraints)
|
modif-tree
|
||||||
|
(-> modif-tree
|
||||||
|
(sizing-auto-modifiers sizing-auto-layouts objects bounds ignore-constraints))
|
||||||
|
|
||||||
modif-tree
|
modif-tree
|
||||||
(cond-> modif-tree
|
(cond-> modif-tree
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
(defn position-pixel-precision
|
(defn position-pixel-precision
|
||||||
[modifiers _ points]
|
[modifiers _ points]
|
||||||
(let [bounds (gpr/points->rect points)
|
(let [bounds (gpr/bounds->rect points)
|
||||||
corner (gpt/point bounds)
|
corner (gpt/point bounds)
|
||||||
target-corner (gpt/round corner)
|
target-corner (gpt/round corner)
|
||||||
deltav (gpt/to-vec corner target-corner)]
|
deltav (gpt/to-vec corner target-corner)]
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
(ns app.common.geom.shapes.points
|
(ns app.common.geom.shapes.points
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.intersect :as gsi]))
|
[app.common.geom.shapes.intersect :as gsi]
|
||||||
|
[app.common.math :as mth]))
|
||||||
|
|
||||||
(defn origin
|
(defn origin
|
||||||
[points]
|
[points]
|
||||||
|
@ -70,45 +71,66 @@
|
||||||
(-> p2 (gpt/add right-v) (gpt/add bottom-v))
|
(-> p2 (gpt/add right-v) (gpt/add bottom-v))
|
||||||
(-> p3 (gpt/add left-v) (gpt/add bottom-v))])))
|
(-> p3 (gpt/add left-v) (gpt/add bottom-v))])))
|
||||||
|
|
||||||
|
(defn- project-t
|
||||||
|
"Given a point and a line returns the parametric t the cross point with the line going through the other axis projected"
|
||||||
|
[point [start end] other-axis-vec]
|
||||||
|
|
||||||
|
(let [line-vec (gpt/to-vec start end)
|
||||||
#_(defn parent-coords-rect
|
pr-point (gsi/line-line-intersect point (gpt/add point other-axis-vec) start end)]
|
||||||
[child-bounds parent-bounds]
|
|
||||||
#_(-> child-bounds
|
|
||||||
(gco/transform-points (:transform-inverse parent))
|
|
||||||
(gpr/points->rect)))
|
|
||||||
|
|
||||||
(defn closest-first
|
|
||||||
"Reorders the points so the closest to the line start-end is the first"
|
|
||||||
[[a b c d] start end]
|
|
||||||
|
|
||||||
(let [da (gpt/point-line-distance a start end)
|
|
||||||
db (gpt/point-line-distance b start end)
|
|
||||||
dc (gpt/point-line-distance c start end)
|
|
||||||
dd (gpt/point-line-distance d start end)]
|
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(and (<= da db) (<= da dc) (<= da dd))
|
(not (mth/almost-zero? (:x line-vec)))
|
||||||
[a b c d]
|
(/ (- (:x pr-point) (:x start)) (:x line-vec))
|
||||||
|
|
||||||
(and (<= db da) (<= db dc) (<= db dd))
|
(not (mth/almost-zero? (:y line-vec)))
|
||||||
[b c d a]
|
(/ (- (:y pr-point) (:y start)) (:y line-vec))
|
||||||
|
|
||||||
(and (<= dc da) (<= dc db) (<= dc dd))
|
|
||||||
[c d a b]
|
|
||||||
|
|
||||||
|
;; Vector is almost zero
|
||||||
:else
|
:else
|
||||||
[d a b c])))
|
0)))
|
||||||
|
|
||||||
(defn parent-coords-bounds
|
(defn parent-coords-bounds
|
||||||
[bounds [p1 p2 _ p4]]
|
[child-bounds [p1 p2 _ p4 :as parent-bounds]]
|
||||||
|
|
||||||
|
(if (empty? child-bounds)
|
||||||
|
parent-bounds
|
||||||
|
|
||||||
|
(let [rh [p1 p2]
|
||||||
|
rv [p1 p4]
|
||||||
|
|
||||||
(let [[b1 b2 b3 b4] (closest-first bounds p1 p2)
|
|
||||||
hv (gpt/to-vec p1 p2)
|
hv (gpt/to-vec p1 p2)
|
||||||
vv (gpt/to-vec p1 p4)
|
vv (gpt/to-vec p1 p4)
|
||||||
|
|
||||||
i1 (gsi/line-line-intersect b1 (gpt/add hv b1) b4 (gpt/add b4 vv))
|
ph #(gpt/add p1 (gpt/scale hv %))
|
||||||
i2 (gsi/line-line-intersect b1 (gpt/add hv b1) b2 (gpt/add b2 vv))
|
pv #(gpt/add p1 (gpt/scale vv %))
|
||||||
i3 (gsi/line-line-intersect b3 (gpt/add hv b3) b2 (gpt/add b2 vv))
|
|
||||||
i4 (gsi/line-line-intersect b3 (gpt/add hv b3) b4 (gpt/add b4 vv))]
|
find-boundary-ts
|
||||||
[i1 i2 i3 i4]))
|
(fn [[th-min th-max tv-min tv-max] current-point]
|
||||||
|
(let [cth (project-t current-point rh vv)
|
||||||
|
ctv (project-t current-point rv hv)]
|
||||||
|
[(min th-min cth)
|
||||||
|
(max th-max cth)
|
||||||
|
(min tv-min ctv)
|
||||||
|
(max tv-max ctv)]))
|
||||||
|
|
||||||
|
[th-min th-max tv-min tv-max]
|
||||||
|
(->> child-bounds (reduce find-boundary-ts [##Inf ##-Inf ##Inf ##-Inf]))
|
||||||
|
|
||||||
|
minv-start (pv tv-min)
|
||||||
|
minv-end (gpt/add minv-start hv)
|
||||||
|
minh-start (ph th-min)
|
||||||
|
minh-end (gpt/add minh-start vv)
|
||||||
|
|
||||||
|
maxv-start (pv tv-max)
|
||||||
|
maxv-end (gpt/add maxv-start hv)
|
||||||
|
maxh-start (ph th-max)
|
||||||
|
maxh-end (gpt/add maxh-start vv)
|
||||||
|
|
||||||
|
i1 (gsi/line-line-intersect minv-start minv-end minh-start minh-end)
|
||||||
|
i2 (gsi/line-line-intersect minv-start minv-end maxh-start maxh-end)
|
||||||
|
i3 (gsi/line-line-intersect maxv-start maxv-end maxh-start maxh-end)
|
||||||
|
i4 (gsi/line-line-intersect maxv-start maxv-end minh-start minh-end)]
|
||||||
|
[i1 i2 i3 i4])))
|
||||||
|
|
||||||
|
(defn merge-parent-coords-bounds
|
||||||
|
[bounds parent-bounds]
|
||||||
|
(parent-coords-bounds (flatten bounds) parent-bounds))
|
||||||
|
|
|
@ -91,6 +91,15 @@
|
||||||
(when (d/num? minx miny maxx maxy)
|
(when (d/num? minx miny maxx maxy)
|
||||||
(make-rect minx miny (- maxx minx) (- maxy miny))))))
|
(make-rect minx miny (- maxx minx) (- maxy miny))))))
|
||||||
|
|
||||||
|
(defn bounds->rect
|
||||||
|
[[{ax :x ay :y} {bx :x by :y} {cx :x cy :y} {dx :x dy :y}]]
|
||||||
|
(let [minx (min ax bx cx dx)
|
||||||
|
miny (min ay by cy dy)
|
||||||
|
maxx (max ax bx cx dx)
|
||||||
|
maxy (max ay by cy dy)]
|
||||||
|
(when (d/num? minx miny maxx maxy)
|
||||||
|
(make-rect minx miny (- maxx minx) (- maxy miny)))))
|
||||||
|
|
||||||
(defn squared-points
|
(defn squared-points
|
||||||
[points]
|
[points]
|
||||||
(when (d/not-empty? points)
|
(when (d/not-empty? points)
|
||||||
|
|
|
@ -463,18 +463,19 @@
|
||||||
(apply-modifiers modifiers)))))
|
(apply-modifiers modifiers)))))
|
||||||
|
|
||||||
(defn apply-objects-modifiers
|
(defn apply-objects-modifiers
|
||||||
[objects modifiers]
|
([objects modifiers]
|
||||||
|
(apply-objects-modifiers objects modifiers (keys modifiers)))
|
||||||
|
|
||||||
|
([objects modifiers ids]
|
||||||
(loop [objects objects
|
(loop [objects objects
|
||||||
entry (first modifiers)
|
ids (seq ids)]
|
||||||
modifiers (rest modifiers)]
|
(if (empty? ids)
|
||||||
|
|
||||||
(if (nil? entry)
|
|
||||||
objects
|
objects
|
||||||
(let [[id modifier] entry]
|
|
||||||
(recur (d/update-when objects id transform-shape (:modifiers modifier))
|
(let [id (first ids)
|
||||||
(first modifiers)
|
modifier (dm/get-in modifiers [id :modifiers])]
|
||||||
(rest modifiers))))))
|
(recur (d/update-when objects id transform-shape modifier)
|
||||||
|
(rest ids)))))))
|
||||||
|
|
||||||
(defn transform-bounds
|
(defn transform-bounds
|
||||||
([points modifiers]
|
([points modifiers]
|
||||||
|
|
|
@ -106,6 +106,12 @@
|
||||||
parent (get objects parent-id)]
|
parent (get objects parent-id)]
|
||||||
(layout? parent)))
|
(layout? parent)))
|
||||||
|
|
||||||
|
(defn layout-child-id? [objects id]
|
||||||
|
(let [shape (get objects id)
|
||||||
|
parent-id (:parent-id shape)
|
||||||
|
parent (get objects parent-id)]
|
||||||
|
(layout? parent)))
|
||||||
|
|
||||||
(defn inside-layout?
|
(defn inside-layout?
|
||||||
"Check if the shape is inside a layout"
|
"Check if the shape is inside a layout"
|
||||||
[objects shape]
|
[objects shape]
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.changes :as dch]
|
||||||
[app.main.data.workspace.selection :as dws]
|
[app.main.data.workspace.selection :as dws]
|
||||||
|
[app.main.data.workspace.shapes-update-layout :as dwul]
|
||||||
[app.main.data.workspace.state-helpers :as wsh]
|
[app.main.data.workspace.state-helpers :as wsh]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
@ -174,15 +175,22 @@
|
||||||
(cph/frame-shape? shape)
|
(cph/frame-shape? shape)
|
||||||
(remove-frame-changes it page-id shape objects))))
|
(remove-frame-changes it page-id shape objects))))
|
||||||
|
|
||||||
|
selected (wsh/lookup-selected state)
|
||||||
changes-list (sequence
|
changes-list (sequence
|
||||||
(keep prepare)
|
(keep prepare)
|
||||||
(wsh/lookup-selected state))
|
selected)
|
||||||
|
|
||||||
|
parents (into #{}
|
||||||
|
(comp (map #(cph/get-parent objects %))
|
||||||
|
(keep :id))
|
||||||
|
selected)
|
||||||
|
|
||||||
changes {:redo-changes (vec (mapcat :redo-changes changes-list))
|
changes {:redo-changes (vec (mapcat :redo-changes changes-list))
|
||||||
:undo-changes (vec (mapcat :undo-changes changes-list))
|
:undo-changes (vec (mapcat :undo-changes changes-list))
|
||||||
:origin it}]
|
:origin it}]
|
||||||
|
|
||||||
(rx/of (dch/commit-changes changes))))))
|
(rx/of (dch/commit-changes changes)
|
||||||
|
(dwul/update-layout-positions parents))))))
|
||||||
|
|
||||||
(def mask-group
|
(def mask-group
|
||||||
(ptk/reify ::mask-group
|
(ptk/reify ::mask-group
|
||||||
|
|
|
@ -443,7 +443,8 @@
|
||||||
|
|
||||||
exclude-frames-siblings
|
exclude-frames-siblings
|
||||||
(into exclude-frames
|
(into exclude-frames
|
||||||
(mapcat (partial cph/get-siblings-ids objects))
|
(comp (mapcat (partial cph/get-siblings-ids objects))
|
||||||
|
(filter (partial ctl/layout-child-id? objects)))
|
||||||
selected)
|
selected)
|
||||||
|
|
||||||
fix-axis
|
fix-axis
|
||||||
|
|
|
@ -80,7 +80,8 @@
|
||||||
modifiers (mf/deref refs/workspace-modifiers)
|
modifiers (mf/deref refs/workspace-modifiers)
|
||||||
|
|
||||||
objects-modified (mf/with-memo [base-objects modifiers]
|
objects-modified (mf/with-memo [base-objects modifiers]
|
||||||
(gsh/apply-objects-modifiers base-objects modifiers))
|
(gsh/apply-objects-modifiers base-objects modifiers selected))
|
||||||
|
|
||||||
background (get options :background clr/canvas)
|
background (get options :background clr/canvas)
|
||||||
|
|
||||||
;; STATE
|
;; STATE
|
||||||
|
@ -423,8 +424,14 @@
|
||||||
:hover-top-frame-id @hover-top-frame-id
|
:hover-top-frame-id @hover-top-frame-id
|
||||||
:zoom zoom}])
|
:zoom zoom}])
|
||||||
|
|
||||||
|
(when (debug? :layout-content-bounds)
|
||||||
|
[:& wvd/debug-content-bounds {:selected-shapes selected-shapes
|
||||||
|
:objects objects-modified
|
||||||
|
:hover-top-frame-id @hover-top-frame-id
|
||||||
|
:zoom zoom}])
|
||||||
|
|
||||||
(when (debug? :layout-lines)
|
(when (debug? :layout-lines)
|
||||||
[:& wvd/debug-layout {:selected-shapes selected-shapes
|
[:& wvd/debug-layout-lines {:selected-shapes selected-shapes
|
||||||
:objects objects-modified
|
:objects objects-modified
|
||||||
:hover-top-frame-id @hover-top-frame-id
|
:hover-top-frame-id @hover-top-frame-id
|
||||||
:zoom zoom}])
|
:zoom zoom}])
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
;; Helper to debug the bounds when set the "hug" content property
|
;; Helper to debug the bounds when set the "hug" content property
|
||||||
#_(mf/defc debug-layout
|
(mf/defc debug-content-bounds
|
||||||
"Debug component to show the auto-layout drop areas"
|
"Debug component to show the auto-layout drop areas"
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
@ -36,27 +36,12 @@
|
||||||
|
|
||||||
(when (and shape (:layout shape))
|
(when (and shape (:layout shape))
|
||||||
(let [children (cph/get-immediate-children objects (:id shape))
|
(let [children (cph/get-immediate-children objects (:id shape))
|
||||||
layout-data (gsl/calc-layout-data shape children)
|
layout-bounds (gsl/layout-content-bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points])) shape children)]
|
||||||
|
[:g.debug-layout {:pointer-events "none"}
|
||||||
|
[:polygon {:points (->> layout-bounds (map #(dm/fmt "%, %" (:x %) (:y %))) (str/join " "))
|
||||||
|
:style {:stroke "red" :fill "none"}}]]))))
|
||||||
|
|
||||||
{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} (:layout-padding shape)
|
(mf/defc debug-layout-lines
|
||||||
pad-top (or pad-top 0)
|
|
||||||
pad-right (or pad-right 0)
|
|
||||||
pad-bottom (or pad-bottom 0)
|
|
||||||
pad-left (or pad-left 0)
|
|
||||||
|
|
||||||
layout-bounds (gsl/layout-content-bounds shape children)]
|
|
||||||
[:g.debug-layout {:pointer-events "none"
|
|
||||||
:transform (gsh/transform-str shape)}
|
|
||||||
|
|
||||||
|
|
||||||
[:rect {:x (:x layout-bounds)
|
|
||||||
:y (:y layout-bounds)
|
|
||||||
:width (:width layout-bounds)
|
|
||||||
:height (:height layout-bounds)
|
|
||||||
:style {:stroke "red"
|
|
||||||
:fill "none"}}]]))))
|
|
||||||
|
|
||||||
(mf/defc debug-layout
|
|
||||||
"Debug component to show the auto-layout drop areas"
|
"Debug component to show the auto-layout drop areas"
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
|
|
@ -74,6 +74,9 @@
|
||||||
;; Display the layout lines
|
;; Display the layout lines
|
||||||
:layout-lines
|
:layout-lines
|
||||||
|
|
||||||
|
;; Display the bounds for the hug content adjust
|
||||||
|
:layout-content-bounds
|
||||||
|
|
||||||
;; Makes the pixel grid red so its more visibile
|
;; Makes the pixel grid red so its more visibile
|
||||||
:pixel-grid
|
:pixel-grid
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue