mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 18:48:37 -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)
|
||||
(disj 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)]
|
||||
(divide v (point v-length v-length))))
|
||||
|
||||
(defn perpendicular
|
||||
[{:keys [x y]}]
|
||||
(Point. (- y) x))
|
||||
|
||||
(defn project
|
||||
"V1 perpendicular projection on vector V2"
|
||||
[v1 v2]
|
||||
|
|
|
@ -251,9 +251,11 @@
|
|||
|
||||
(defn normalize-modifiers
|
||||
"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)
|
||||
|
||||
scale-x (if (= :scale constraints-h)
|
||||
|
@ -278,7 +280,7 @@
|
|||
resize-transform-inverse))))
|
||||
|
||||
(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)
|
||||
|
||||
|
@ -295,10 +297,13 @@
|
|||
(if (and (= :scale constraints-h) (= :scale constraints-v))
|
||||
modifiers
|
||||
|
||||
(let [child-bounds (:points child)
|
||||
(let [transformed-parent-bounds @transformed-parent-bounds
|
||||
|
||||
modifiers (ctm/select-child-modifiers 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)
|
||||
|
||||
child-points-before (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||
|
|
|
@ -7,21 +7,19 @@
|
|||
(ns app.common.geom.shapes.flex-layout.bounds
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.geom.shapes.points :as gpo]
|
||||
[app.common.geom.shapes.rect :as gre]
|
||||
[app.common.math :as mth]
|
||||
[app.common.types.shape.layout :as ctl]))
|
||||
|
||||
(defn- child-layout-bound-points
|
||||
"Returns the bounds of the children as points"
|
||||
[parent child]
|
||||
[parent child parent-bounds child-bounds]
|
||||
|
||||
(let [row? (ctl/row? parent)
|
||||
col? (ctl/col? parent)
|
||||
|
||||
hv (partial gpo/start-hv (:points parent))
|
||||
vv (partial gpo/start-vv (:points parent))
|
||||
hv (partial gpo/start-hv parent-bounds)
|
||||
vv (partial gpo/start-vv parent-bounds)
|
||||
|
||||
v-start? (ctl/v-start? parent)
|
||||
v-center? (ctl/v-center? parent)
|
||||
|
@ -30,10 +28,10 @@
|
|||
h-center? (ctl/h-center? parent)
|
||||
h-end? (ctl/h-end? parent)
|
||||
|
||||
base-p (first (:points child))
|
||||
base-p (gpo/origin child-bounds)
|
||||
|
||||
width (-> child :selrect :width)
|
||||
height (-> child :selrect :height)
|
||||
width (gpo/width-points child-bounds)
|
||||
height (gpo/height-points child-bounds)
|
||||
|
||||
min-width (if (ctl/fill-width? child)
|
||||
(ctl/child-min-width child)
|
||||
|
@ -91,22 +89,29 @@
|
|||
(gpt/subtract (vv min-height)))))))
|
||||
|
||||
(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-right (or pad-right 0)
|
||||
pad-bottom (or pad-bottom 0)
|
||||
pad-left (or pad-left 0)
|
||||
|
||||
child-bounds
|
||||
(fn [{:keys [points] :as child}]
|
||||
(if (or (ctl/fill-height? child) (ctl/fill-height? child))
|
||||
(child-layout-bound-points parent child)
|
||||
points))]
|
||||
(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))
|
||||
(child-layout-bound-points parent child parent-bounds parent-bounds)
|
||||
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
|
||||
"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)
|
||||
parent-bounds (:points parent)
|
||||
|
||||
transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
||||
(let [transformed-child-bounds (gtr/transform-bounds child-bounds modifiers)
|
||||
|
||||
child-bb-before (gpo/parent-coords-bounds child-bounds 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))
|
||||
|
||||
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)
|
||||
resize-transform (gmt/multiply modif-transform transform)
|
||||
resize-transform-inverse (gmt/multiply transform-inverse modif-transform-inverse)
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
|
||||
(defn- set-children-modifiers
|
||||
"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)
|
||||
modifiers (dm/get-in modif-tree [(:id parent) :modifiers])]
|
||||
|
||||
|
@ -106,59 +106,67 @@
|
|||
modif-tree))
|
||||
|
||||
;; 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
|
||||
children (seq children)]
|
||||
(if (empty? children)
|
||||
modif-tree
|
||||
(let [child-id (first children)
|
||||
child (get objects child-id)
|
||||
child-modifiers (gct/calc-child-modifiers parent child modifiers ignore-constraints parent-bounds @transformed-parent-bounds)]
|
||||
(let [child-id (first children)
|
||||
child (get objects child-id)
|
||||
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
|
||||
(not (ctm/empty? child-modifiers))
|
||||
(update-in [child-id :modifiers] ctm/add-modifiers child-modifiers))
|
||||
(rest 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]
|
||||
(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
|
||||
(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
|
||||
(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))]
|
||||
(reduce process-child modif-tree children))))
|
||||
|
||||
|
||||
(defn get-bounds
|
||||
[objects modif-tree shape]
|
||||
|
||||
(let [modifiers (-> (dm/get-in modif-tree [(:id shape) :modifiers])
|
||||
(defn get-group-bounds
|
||||
[objects bounds modif-tree shape]
|
||||
(let [shape-id (:id shape)
|
||||
modifiers (-> (dm/get-in modif-tree [shape-id :modifiers])
|
||||
(ctm/select-geometry))
|
||||
|
||||
children (cph/get-immediate-children objects (:id shape))
|
||||
bounds (cond
|
||||
(cph/group-shape? shape)
|
||||
(let [children-bounds (->> children (mapv (partial get-bounds objects modif-tree)))]
|
||||
(gtr/group-bounds shape children-bounds))
|
||||
children (cph/get-immediate-children objects shape-id)
|
||||
group-bounds
|
||||
(cond
|
||||
(cph/group-shape? shape)
|
||||
(let [children-bounds (->> children (mapv #(get-group-bounds objects bounds modif-tree %)))]
|
||||
(gtr/group-bounds shape children-bounds))
|
||||
|
||||
(cph/mask-shape? shape)
|
||||
(get-bounds objects modif-tree (-> children first))
|
||||
(cph/mask-shape? shape)
|
||||
(get-group-bounds objects bounds modif-tree (-> children first))
|
||||
|
||||
:else
|
||||
(:points shape))]
|
||||
|
||||
(gtr/transform-bounds bounds modifiers)))
|
||||
:else
|
||||
@(get bounds shape-id))]
|
||||
|
||||
(cond-> group-bounds
|
||||
(not (ctm/empty? modifiers))
|
||||
(gtr/transform-bounds modifiers))))
|
||||
|
||||
(defn- set-layout-modifiers
|
||||
[modif-tree objects parent transformed-parent-bounds]
|
||||
[modif-tree objects bounds parent transformed-parent-bounds]
|
||||
|
||||
(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))
|
||||
child])
|
||||
|
||||
|
@ -195,57 +203,63 @@
|
|||
|
||||
(defn- calc-auto-modifiers
|
||||
"Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes"
|
||||
[objects parent]
|
||||
(letfn [(set-parent-auto-width
|
||||
[modifiers auto-width]
|
||||
(let [origin (-> parent :points first)
|
||||
scale-width (/ auto-width (-> parent :selrect :width) )]
|
||||
(-> modifiers
|
||||
(ctm/resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
|
||||
[objects bounds parent]
|
||||
(let [parent-id (:id parent)
|
||||
parent-bounds (get bounds parent-id)
|
||||
|
||||
(set-parent-auto-height
|
||||
[modifiers auto-height]
|
||||
(let [origin (-> parent :points first)
|
||||
scale-height (/ auto-height (-> parent :selrect :height) )]
|
||||
(-> modifiers
|
||||
(ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))]
|
||||
set-parent-auto-width
|
||||
(fn [modifiers auto-width]
|
||||
(let [origin (gpo/origin @parent-bounds)
|
||||
scale-width (/ auto-width (gpo/width-points @parent-bounds))]
|
||||
(-> modifiers
|
||||
(ctm/resize-parent (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
|
||||
|
||||
(let [children (->> parent :shapes (map (d/getf objects)))
|
||||
{auto-width :width auto-height :height}
|
||||
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
|
||||
(gcl/layout-content-bounds parent children))]
|
||||
(cond-> (ctm/empty)
|
||||
(and (some? auto-width) (ctl/auto-width? parent))
|
||||
(set-parent-auto-width auto-width)
|
||||
set-parent-auto-height
|
||||
(fn [modifiers auto-height]
|
||||
(let [origin (gpo/origin @parent-bounds)
|
||||
scale-height (/ auto-height (gpo/height-points @parent-bounds))]
|
||||
(-> modifiers
|
||||
(ctm/resize-parent (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))
|
||||
|
||||
(and (some? auto-height) (ctl/auto-height? parent))
|
||||
(set-parent-auto-height auto-height)))))
|
||||
children (->> parent :shapes (map (d/getf objects)))
|
||||
content-bounds
|
||||
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
|
||||
(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)
|
||||
(and (some? auto-width) (ctl/auto-width? parent))
|
||||
(set-parent-auto-width auto-width)
|
||||
|
||||
(and (some? auto-height) (ctl/auto-height? parent))
|
||||
(set-parent-auto-height auto-height))))
|
||||
|
||||
(defn- propagate-modifiers
|
||||
"Propagate modifiers to its children"
|
||||
[objects ignore-constraints [modif-tree autolayouts] parent]
|
||||
(let [parent-id (:id parent)
|
||||
root? (= uuid/zero parent-id)
|
||||
modifiers (-> (dm/get-in modif-tree [parent-id :modifiers])
|
||||
(ctm/select-geometry))
|
||||
|
||||
transformed-parent-bounds (delay (gtr/transform-bounds (:points parent) modifiers))
|
||||
|
||||
[objects bounds ignore-constraints [modif-tree autolayouts] parent]
|
||||
(let [parent-id (:id parent)
|
||||
root? (= uuid/zero parent-id)
|
||||
modifiers (-> (dm/get-in modif-tree [parent-id :modifiers])
|
||||
(ctm/select-geometry))
|
||||
has-modifiers? (ctm/child-modifiers? modifiers)
|
||||
layout? (ctl/layout? parent)
|
||||
auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
|
||||
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
||||
layout? (ctl/layout? parent)
|
||||
auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
|
||||
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
||||
|
||||
;; 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
|
||||
(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?
|
||||
(-> (process-layout-children objects parent transformed-parent-bounds)
|
||||
(set-layout-modifiers objects parent transformed-parent-bounds)))
|
||||
(-> (process-layout-children objects bounds 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
|
||||
(cond-> autolayouts auto? (conj (:id parent)))]))
|
||||
|
@ -258,28 +272,6 @@
|
|||
(update id ctm/apply-structure-modifiers modifiers)))]
|
||||
(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
|
||||
[modif-tree other-tree]
|
||||
(reduce (fn [modif-tree [id {:keys [modifiers]}]]
|
||||
|
@ -287,41 +279,58 @@
|
|||
modif-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
|
||||
"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
|
||||
bounds (transform-bounds bounds objects 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)}}
|
||||
{current {:modifiers (calc-auto-modifiers objects bounds parent-base)}}
|
||||
|
||||
tree-seq (resolve-tree-sequence #{current} objects)
|
||||
|
||||
[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)]
|
||||
(recur modif-tree (rest sizing-auto-layouts)))
|
||||
(recur modif-tree bounds (rest sizing-auto-layouts)))
|
||||
modif-tree)))
|
||||
|
||||
(defn set-objects-modifiers
|
||||
[modif-tree objects ignore-constraints snap-pixel?]
|
||||
|
||||
(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)
|
||||
|
||||
[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
|
||||
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
|
||||
(cond-> modif-tree
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
(defn position-pixel-precision
|
||||
[modifiers _ points]
|
||||
(let [bounds (gpr/points->rect points)
|
||||
(let [bounds (gpr/bounds->rect points)
|
||||
corner (gpt/point bounds)
|
||||
target-corner (gpt/round corner)
|
||||
deltav (gpt/to-vec corner target-corner)]
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
(ns app.common.geom.shapes.points
|
||||
(:require
|
||||
[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
|
||||
[points]
|
||||
|
@ -70,45 +71,66 @@
|
|||
(-> p2 (gpt/add right-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]
|
||||
|
||||
|
||||
#_(defn parent-coords-rect
|
||||
[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)]
|
||||
|
||||
(let [line-vec (gpt/to-vec start end)
|
||||
pr-point (gsi/line-line-intersect point (gpt/add point other-axis-vec) start end)]
|
||||
(cond
|
||||
(and (<= da db) (<= da dc) (<= da dd))
|
||||
[a b c d]
|
||||
(not (mth/almost-zero? (:x line-vec)))
|
||||
(/ (- (:x pr-point) (:x start)) (:x line-vec))
|
||||
|
||||
(and (<= db da) (<= db dc) (<= db dd))
|
||||
[b c d a]
|
||||
|
||||
(and (<= dc da) (<= dc db) (<= dc dd))
|
||||
[c d a b]
|
||||
(not (mth/almost-zero? (:y line-vec)))
|
||||
(/ (- (:y pr-point) (:y start)) (:y line-vec))
|
||||
|
||||
;; Vector is almost zero
|
||||
:else
|
||||
[d a b c])))
|
||||
0)))
|
||||
|
||||
(defn parent-coords-bounds
|
||||
[bounds [p1 p2 _ p4]]
|
||||
[child-bounds [p1 p2 _ p4 :as parent-bounds]]
|
||||
|
||||
(let [[b1 b2 b3 b4] (closest-first bounds p1 p2)
|
||||
hv (gpt/to-vec p1 p2)
|
||||
vv (gpt/to-vec p1 p4)
|
||||
(if (empty? child-bounds)
|
||||
parent-bounds
|
||||
|
||||
i1 (gsi/line-line-intersect b1 (gpt/add hv b1) b4 (gpt/add b4 vv))
|
||||
i2 (gsi/line-line-intersect b1 (gpt/add hv b1) b2 (gpt/add b2 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))]
|
||||
[i1 i2 i3 i4]))
|
||||
(let [rh [p1 p2]
|
||||
rv [p1 p4]
|
||||
|
||||
hv (gpt/to-vec p1 p2)
|
||||
vv (gpt/to-vec p1 p4)
|
||||
|
||||
ph #(gpt/add p1 (gpt/scale hv %))
|
||||
pv #(gpt/add p1 (gpt/scale vv %))
|
||||
|
||||
find-boundary-ts
|
||||
(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)
|
||||
(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
|
||||
[points]
|
||||
(when (d/not-empty? points)
|
||||
|
|
|
@ -463,18 +463,19 @@
|
|||
(apply-modifiers modifiers)))))
|
||||
|
||||
(defn apply-objects-modifiers
|
||||
[objects modifiers]
|
||||
([objects modifiers]
|
||||
(apply-objects-modifiers objects modifiers (keys modifiers)))
|
||||
|
||||
(loop [objects objects
|
||||
entry (first modifiers)
|
||||
modifiers (rest modifiers)]
|
||||
([objects modifiers ids]
|
||||
(loop [objects objects
|
||||
ids (seq ids)]
|
||||
(if (empty? ids)
|
||||
objects
|
||||
|
||||
(if (nil? entry)
|
||||
objects
|
||||
(let [[id modifier] entry]
|
||||
(recur (d/update-when objects id transform-shape (:modifiers modifier))
|
||||
(first modifiers)
|
||||
(rest modifiers))))))
|
||||
(let [id (first ids)
|
||||
modifier (dm/get-in modifiers [id :modifiers])]
|
||||
(recur (d/update-when objects id transform-shape modifier)
|
||||
(rest ids)))))))
|
||||
|
||||
(defn transform-bounds
|
||||
([points modifiers]
|
||||
|
|
|
@ -106,6 +106,12 @@
|
|||
parent (get objects parent-id)]
|
||||
(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?
|
||||
"Check if the shape is inside a layout"
|
||||
[objects shape]
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.common.types.shape-tree :as ctt]
|
||||
[app.main.data.workspace.changes :as dch]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shapes-update-layout :as dwul]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[beicon.core :as rx]
|
||||
[potok.core :as ptk]))
|
||||
|
@ -174,15 +175,22 @@
|
|||
(cph/frame-shape? shape)
|
||||
(remove-frame-changes it page-id shape objects))))
|
||||
|
||||
selected (wsh/lookup-selected state)
|
||||
changes-list (sequence
|
||||
(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))
|
||||
:undo-changes (vec (mapcat :undo-changes changes-list))
|
||||
:origin it}]
|
||||
|
||||
(rx/of (dch/commit-changes changes))))))
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwul/update-layout-positions parents))))))
|
||||
|
||||
(def mask-group
|
||||
(ptk/reify ::mask-group
|
||||
|
|
|
@ -443,7 +443,8 @@
|
|||
|
||||
exclude-frames-siblings
|
||||
(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)
|
||||
|
||||
fix-axis
|
||||
|
|
|
@ -80,7 +80,8 @@
|
|||
modifiers (mf/deref refs/workspace-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)
|
||||
|
||||
;; STATE
|
||||
|
@ -423,11 +424,17 @@
|
|||
:hover-top-frame-id @hover-top-frame-id
|
||||
: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)
|
||||
[:& wvd/debug-layout {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
[:& wvd/debug-layout-lines {:selected-shapes selected-shapes
|
||||
:objects objects-modified
|
||||
:hover-top-frame-id @hover-top-frame-id
|
||||
:zoom zoom}])
|
||||
|
||||
(when (debug? :parent-bounds)
|
||||
[:& wvd/debug-parent-bounds {:selected-shapes selected-shapes
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
[rumext.v2 :as mf]))
|
||||
|
||||
;; 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"
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
@ -36,27 +36,12 @@
|
|||
|
||||
(when (and shape (:layout 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)
|
||||
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
|
||||
(mf/defc debug-layout-lines
|
||||
"Debug component to show the auto-layout drop areas"
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
;; Display the layout lines
|
||||
:layout-lines
|
||||
|
||||
;; Display the bounds for the hug content adjust
|
||||
:layout-content-bounds
|
||||
|
||||
;; Makes the pixel grid red so its more visibile
|
||||
:pixel-grid
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue