mirror of
https://github.com/penpot/penpot.git
synced 2025-08-07 14:38:33 +02:00
Merge pull request #3708 from penpot/alotor-grid-performance
Layouts performance
This commit is contained in:
commit
69c8845ac8
11 changed files with 655 additions and 482 deletions
|
@ -884,3 +884,13 @@
|
||||||
(extend-protocol ICloseable
|
(extend-protocol ICloseable
|
||||||
AutoCloseable
|
AutoCloseable
|
||||||
(close! [this] (.close this))))
|
(close! [this] (.close this))))
|
||||||
|
|
||||||
|
(defn take-until
|
||||||
|
"Returns a lazy sequence of successive items from coll until
|
||||||
|
(pred item) returns true, including that item"
|
||||||
|
([pred]
|
||||||
|
(halt-when pred (fn [r h] (conj r h))))
|
||||||
|
|
||||||
|
([pred coll]
|
||||||
|
(transduce (take-until pred) conj [] coll)))
|
||||||
|
|
||||||
|
|
133
common/src/app/common/geom/bounds_map.cljc
Normal file
133
common/src/app/common/geom/bounds_map.cljc
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.common.geom.bounds-map
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.geom.shapes.common :as gco]
|
||||||
|
[app.common.geom.shapes.points :as gpo]
|
||||||
|
[app.common.geom.shapes.transforms :as gtr]
|
||||||
|
[app.common.math :as mth]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.types.modifiers :as ctm]
|
||||||
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
|
(defn objects->bounds-map
|
||||||
|
[objects]
|
||||||
|
(d/lazy-map
|
||||||
|
(keys objects)
|
||||||
|
#(gco/shape->points (get objects %))))
|
||||||
|
|
||||||
|
(defn- create-bounds
|
||||||
|
"Create the bounds object for the current shape in this context"
|
||||||
|
([shape bounds-map objects]
|
||||||
|
(create-bounds shape bounds-map objects nil nil))
|
||||||
|
|
||||||
|
([shape bounds-map objects modif-tree]
|
||||||
|
(create-bounds shape bounds-map objects modif-tree nil))
|
||||||
|
|
||||||
|
([{:keys [id] :as shape} bounds-map objects modif-tree current-ref]
|
||||||
|
(cond
|
||||||
|
(and (cph/mask-shape? shape) (d/not-empty? (:shapes shape)))
|
||||||
|
(create-bounds (get objects (first (:shapes shape))) bounds-map objects modif-tree)
|
||||||
|
|
||||||
|
(cph/group-shape? shape)
|
||||||
|
(let [modifiers (dm/get-in modif-tree [id :modifiers])
|
||||||
|
children (cph/get-immediate-children objects id)
|
||||||
|
shape-bounds (if current-ref @current-ref @(get bounds-map id))
|
||||||
|
current-bounds
|
||||||
|
(cond-> shape-bounds
|
||||||
|
(not (ctm/empty? modifiers))
|
||||||
|
(gtr/transform-bounds modifiers))
|
||||||
|
|
||||||
|
children-bounds
|
||||||
|
(->> children
|
||||||
|
(mapv #(deref (get bounds-map (:id %)))))]
|
||||||
|
(gpo/merge-parent-coords-bounds children-bounds current-bounds))
|
||||||
|
|
||||||
|
:else
|
||||||
|
(let [modifiers (dm/get-in modif-tree [id :modifiers])
|
||||||
|
shape-bounds (if current-ref @current-ref @(get bounds-map id))]
|
||||||
|
(cond-> shape-bounds
|
||||||
|
(not (ctm/empty? modifiers))
|
||||||
|
(gtr/transform-bounds modifiers))))))
|
||||||
|
|
||||||
|
#?(:clj
|
||||||
|
(defn- resolve-modif-tree-ids
|
||||||
|
[objects modif-tree]
|
||||||
|
;; These are the new bounds calculated. Are the "modified" plus any groups they belong to
|
||||||
|
(let [ids (keys modif-tree)]
|
||||||
|
(into (set ids)
|
||||||
|
(mapcat #(->> (cph/get-parent-ids-seq objects %)
|
||||||
|
(take-while (partial cph/group-like-shape? objects))))
|
||||||
|
ids)))
|
||||||
|
|
||||||
|
:cljs
|
||||||
|
;; More performant version using javascript mutable sets
|
||||||
|
(defn- resolve-modif-tree-ids
|
||||||
|
[objects modif-tree]
|
||||||
|
|
||||||
|
(let [base-ids (keys modif-tree)
|
||||||
|
ids (js/Set. base-ids)]
|
||||||
|
(loop [base-ids (seq base-ids)]
|
||||||
|
(when (some? base-ids)
|
||||||
|
(let [cid (first base-ids)]
|
||||||
|
(loop [new-ids
|
||||||
|
(->> (cph/get-parent-seq objects cid)
|
||||||
|
(take-while #(and (cph/group-like-shape? %)
|
||||||
|
(not (.has ids %))))
|
||||||
|
(seq))]
|
||||||
|
(when (some? new-ids)
|
||||||
|
(.add ids (first new-ids))
|
||||||
|
(recur (next new-ids))))
|
||||||
|
(recur (next base-ids)))))
|
||||||
|
ids)))
|
||||||
|
|
||||||
|
(defn transform-bounds-map
|
||||||
|
([bounds-map objects modif-tree]
|
||||||
|
(transform-bounds-map bounds-map objects modif-tree nil))
|
||||||
|
([bounds-map objects modif-tree ids]
|
||||||
|
;; We use the volatile in order to solve the dependencies problem. We want the groups to reference the new
|
||||||
|
;; bounds instead of the old ones. The current as last parameter is to fix a possible infinite loop
|
||||||
|
;; with self-references
|
||||||
|
(let [bm-holder (volatile! nil)
|
||||||
|
|
||||||
|
ids (or ids (resolve-modif-tree-ids objects modif-tree))
|
||||||
|
|
||||||
|
new-bounds-map
|
||||||
|
(loop [tr-bounds-map (transient bounds-map)
|
||||||
|
ids (seq ids)]
|
||||||
|
(if (not ids)
|
||||||
|
(persistent! tr-bounds-map)
|
||||||
|
(let [shape-id (first ids)]
|
||||||
|
(recur
|
||||||
|
(cond-> tr-bounds-map
|
||||||
|
(not= uuid/zero shape-id)
|
||||||
|
(assoc! shape-id
|
||||||
|
(delay (create-bounds (get objects shape-id)
|
||||||
|
@bm-holder
|
||||||
|
objects
|
||||||
|
modif-tree
|
||||||
|
(get bounds-map shape-id)))))
|
||||||
|
(next ids)))))]
|
||||||
|
(vreset! bm-holder new-bounds-map)
|
||||||
|
new-bounds-map)))
|
||||||
|
|
||||||
|
;; Tool for debugging
|
||||||
|
(defn bounds-map
|
||||||
|
[objects bounds-map]
|
||||||
|
(letfn [(parse-bound [[id bounds*]]
|
||||||
|
(let [bounds (deref bounds*)
|
||||||
|
shape (get objects id)]
|
||||||
|
(when (and shape bounds)
|
||||||
|
[(:name shape)
|
||||||
|
{:x (mth/round (:x (gpo/origin bounds)) 2)
|
||||||
|
:y (mth/round (:y (gpo/origin bounds)) 2)
|
||||||
|
:width (mth/round (gpo/width-points bounds) 2)
|
||||||
|
:height (mth/round (gpo/height-points bounds) 2)}])))]
|
||||||
|
|
||||||
|
(into {} (keep parse-bound) bounds-map)))
|
56
common/src/app/common/geom/modif_tree.cljc
Normal file
56
common/src/app/common/geom/modif_tree.cljc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.common.geom.modif-tree
|
||||||
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.geom.shapes.min-size-layout]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.types.modifiers :as ctm]))
|
||||||
|
|
||||||
|
(defn add-modifiers
|
||||||
|
"Add the given modifiers to the map of modifiers."
|
||||||
|
[modif-tree id modifiers]
|
||||||
|
(if (ctm/empty? modifiers)
|
||||||
|
modif-tree
|
||||||
|
(let [old-modifiers
|
||||||
|
(dm/get-in modif-tree [id :modifiers])
|
||||||
|
new-modifiers
|
||||||
|
(ctm/add-modifiers old-modifiers modifiers)]
|
||||||
|
(cond-> modif-tree
|
||||||
|
(ctm/empty? new-modifiers)
|
||||||
|
(dissoc id)
|
||||||
|
|
||||||
|
(not (ctm/empty? new-modifiers))
|
||||||
|
(assoc-in [id :modifiers] new-modifiers)))))
|
||||||
|
|
||||||
|
(defn merge-modif-tree
|
||||||
|
"Merge two maps of modifiers into a single one"
|
||||||
|
[modif-tree other-tree]
|
||||||
|
(reduce
|
||||||
|
(fn [modif-tree [id {:keys [modifiers]}]]
|
||||||
|
(add-modifiers modif-tree id modifiers))
|
||||||
|
modif-tree
|
||||||
|
other-tree))
|
||||||
|
|
||||||
|
(defn apply-structure-modifiers
|
||||||
|
"Only applies the structure modifiers to the objects tree map"
|
||||||
|
[objects modif-tree]
|
||||||
|
(letfn [(update-children-structure-modifiers
|
||||||
|
[objects ids modifiers]
|
||||||
|
(reduce #(update %1 %2 ctm/apply-structure-modifiers modifiers) objects ids))
|
||||||
|
|
||||||
|
(apply-shape [objects [id {:keys [modifiers]}]]
|
||||||
|
(cond-> objects
|
||||||
|
(ctm/has-structure? modifiers)
|
||||||
|
(update id ctm/apply-structure-modifiers modifiers)
|
||||||
|
|
||||||
|
(and (ctm/has-structure? modifiers)
|
||||||
|
(ctm/has-structure-child? modifiers))
|
||||||
|
(update-children-structure-modifiers
|
||||||
|
(cph/get-children-ids objects id)
|
||||||
|
(ctm/select-child-structre-modifiers modifiers))))]
|
||||||
|
(reduce apply-shape objects modif-tree)))
|
|
@ -280,11 +280,11 @@
|
||||||
(/ (gpo/height-points child-bb-before) (max 0.01 (gpo/height-points child-bb-after))))
|
(/ (gpo/height-points child-bb-before) (max 0.01 (gpo/height-points child-bb-after))))
|
||||||
|
|
||||||
resize-vector (gpt/point scale-x scale-y)
|
resize-vector (gpt/point scale-x scale-y)
|
||||||
resize-origin (gpo/origin transformed-child-bounds)
|
resize-origin (gpo/origin child-bb-after)
|
||||||
|
|
||||||
center (gco/points->center transformed-child-bounds)
|
center (gco/points->center child-bb-after)
|
||||||
selrect (gtr/calculate-selrect transformed-child-bounds center)
|
selrect (gtr/calculate-selrect child-bb-after center)
|
||||||
transform (gtr/calculate-transform transformed-child-bounds center selrect)
|
transform (gtr/calculate-transform child-bb-after center selrect)
|
||||||
transform-inverse (when (some? transform) (gmt/inverse transform))]
|
transform-inverse (when (some? transform) (gmt/inverse transform))]
|
||||||
|
|
||||||
(ctm/resize modifiers resize-vector resize-origin transform transform-inverse)))
|
(ctm/resize modifiers resize-vector resize-origin transform transform-inverse)))
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.common.geom.shapes.flex-layout.bounds
|
(ns app.common.geom.shapes.flex-layout.bounds
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.points :as gpo]
|
[app.common.geom.shapes.points :as gpo]
|
||||||
[app.common.types.shape.layout :as ctl]))
|
[app.common.types.shape.layout :as ctl]))
|
||||||
|
@ -31,7 +32,6 @@
|
||||||
(child-layout-bound-points parent child parent-bounds child-bounds (gpt/point) bounds objects))
|
(child-layout-bound-points parent child parent-bounds child-bounds (gpt/point) bounds objects))
|
||||||
|
|
||||||
([parent child parent-bounds child-bounds correct-v bounds objects]
|
([parent child parent-bounds child-bounds correct-v bounds objects]
|
||||||
|
|
||||||
(let [row? (ctl/row? parent)
|
(let [row? (ctl/row? parent)
|
||||||
col? (ctl/col? parent)
|
col? (ctl/col? parent)
|
||||||
|
|
||||||
|
@ -56,7 +56,8 @@
|
||||||
;; This is the leftmost (when row) or topmost (when col) point
|
;; This is the leftmost (when row) or topmost (when col) point
|
||||||
;; Will be added always to the bounds and then calculated the other limits
|
;; Will be added always to the bounds and then calculated the other limits
|
||||||
;; from there
|
;; from there
|
||||||
base-p (cond-> base-p
|
base-p
|
||||||
|
(cond-> base-p
|
||||||
(and row? v-center?)
|
(and row? v-center?)
|
||||||
(gpt/add (vv (/ height 2)))
|
(gpt/add (vv (/ height 2)))
|
||||||
|
|
||||||
|
@ -76,10 +77,12 @@
|
||||||
base-p (gpt/add base-p correct-v)
|
base-p (gpt/add base-p correct-v)
|
||||||
|
|
||||||
result
|
result
|
||||||
(cond-> [base-p
|
[base-p
|
||||||
(gpt/add base-p (hv 0.01))
|
(gpt/add base-p (hv 0.01))
|
||||||
(gpt/add base-p (vv 0.01))]
|
(gpt/add base-p (vv 0.01))]
|
||||||
|
|
||||||
|
result
|
||||||
|
(cond-> result
|
||||||
col?
|
col?
|
||||||
(conj (gpt/add base-p (vv min-height)))
|
(conj (gpt/add base-p (vv min-height)))
|
||||||
|
|
||||||
|
@ -112,18 +115,26 @@
|
||||||
(gpt/subtract (hv (+ width min-width)))
|
(gpt/subtract (hv (+ width min-width)))
|
||||||
|
|
||||||
(and col? (ctl/fill-height? child))
|
(and col? (ctl/fill-height? child))
|
||||||
(gpt/subtract (vv (+ height min-height)))
|
(gpt/subtract (vv (+ height min-height))))]
|
||||||
)]
|
|
||||||
[result correct-v])))
|
[result correct-v])))
|
||||||
|
|
||||||
(defn layout-content-points
|
(defn layout-content-points
|
||||||
[bounds parent children objects]
|
[bounds parent children objects]
|
||||||
|
|
||||||
(let [parent-id (:id parent)
|
(let [parent-id (dm/get-prop parent :id)
|
||||||
parent-bounds @(get bounds parent-id)
|
parent-bounds @(get bounds parent-id)
|
||||||
get-child-bounds
|
reverse? (ctl/reverse? parent)
|
||||||
(fn [[result correct-v] child]
|
children (cond->> children (not reverse?) reverse)]
|
||||||
(let [child-id (:id child)
|
|
||||||
|
(loop [children (seq children)
|
||||||
|
result (transient [])
|
||||||
|
correct-v (gpt/point 0)]
|
||||||
|
|
||||||
|
(if (not children)
|
||||||
|
(persistent! result)
|
||||||
|
|
||||||
|
(let [child (first children)
|
||||||
|
child-id (dm/get-prop child :id)
|
||||||
child-bounds @(get bounds child-id)
|
child-bounds @(get bounds child-id)
|
||||||
[margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
|
[margin-top margin-right margin-bottom margin-left] (ctl/child-margins child)
|
||||||
|
|
||||||
|
@ -137,16 +148,9 @@
|
||||||
(-> (gpo/parent-coords-bounds child-bounds parent-bounds)
|
(-> (gpo/parent-coords-bounds child-bounds parent-bounds)
|
||||||
(gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))]
|
(gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))]
|
||||||
|
|
||||||
[(cond-> result (some? child-bounds) (conj child-bounds))
|
(recur (next children)
|
||||||
correct-v]))
|
(cond-> result (some? child-bounds) (conj! child-bounds))
|
||||||
|
correct-v))))))
|
||||||
reverse? (ctl/reverse? parent)
|
|
||||||
children (cond->> children (not reverse?) reverse)]
|
|
||||||
|
|
||||||
(->> children
|
|
||||||
(remove ctl/layout-absolute?)
|
|
||||||
(reduce get-child-bounds [[] (gpt/point 0)])
|
|
||||||
(first))))
|
|
||||||
|
|
||||||
(defn layout-content-bounds
|
(defn layout-content-bounds
|
||||||
[bounds {:keys [layout-padding] :as parent} children objects]
|
[bounds {:keys [layout-padding] :as parent} children objects]
|
||||||
|
|
|
@ -53,11 +53,11 @@
|
||||||
layout-height (gpo/height-points layout-bounds)]
|
layout-height (gpo/height-points layout-bounds)]
|
||||||
|
|
||||||
(loop [line-data nil
|
(loop [line-data nil
|
||||||
result []
|
result (transient [])
|
||||||
children (seq children)]
|
children (seq children)]
|
||||||
|
|
||||||
(if (empty? children)
|
(if (not children)
|
||||||
(cond-> result (some? line-data) (conj line-data))
|
(persistent! (cond-> result (some? line-data) (conj! line-data)))
|
||||||
|
|
||||||
(let [[child-bounds child] (first children)
|
(let [[child-bounds child] (first children)
|
||||||
{:keys [line-min-width line-min-height
|
{:keys [line-min-width line-min-height
|
||||||
|
@ -91,7 +91,8 @@
|
||||||
next-max-width (+ child-margin-width (:child-max-width child-data))
|
next-max-width (+ child-margin-width (:child-max-width child-data))
|
||||||
next-max-height (+ child-margin-height (:child-max-height child-data))
|
next-max-height (+ child-margin-height (:child-max-height child-data))
|
||||||
|
|
||||||
total-gap-col (cond
|
total-gap-col
|
||||||
|
(cond
|
||||||
space-evenly?
|
space-evenly?
|
||||||
(* layout-gap-col (+ num-children 2))
|
(* layout-gap-col (+ num-children 2))
|
||||||
|
|
||||||
|
@ -101,7 +102,8 @@
|
||||||
:else
|
:else
|
||||||
(* layout-gap-col num-children))
|
(* layout-gap-col num-children))
|
||||||
|
|
||||||
total-gap-row (cond
|
total-gap-row
|
||||||
|
(cond
|
||||||
space-evenly?
|
space-evenly?
|
||||||
(* layout-gap-row (+ num-children 2))
|
(* layout-gap-row (+ num-children 2))
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@
|
||||||
:num-children (inc num-children)
|
:num-children (inc num-children)
|
||||||
:children-data (conjv children-data child-data)}
|
:children-data (conjv children-data child-data)}
|
||||||
result
|
result
|
||||||
(rest children))
|
(next children))
|
||||||
|
|
||||||
(recur {:line-min-width next-min-width
|
(recur {:line-min-width next-min-width
|
||||||
:line-min-height next-min-height
|
:line-min-height next-min-height
|
||||||
|
@ -136,29 +138,31 @@
|
||||||
:line-max-height next-max-height
|
:line-max-height next-max-height
|
||||||
:num-children 1
|
:num-children 1
|
||||||
:children-data [child-data]}
|
:children-data [child-data]}
|
||||||
(cond-> result (some? line-data) (conj line-data))
|
(cond-> result (some? line-data) (conj! line-data))
|
||||||
(rest children))))))))
|
(next children))))))))
|
||||||
|
|
||||||
(defn add-space-to-items
|
(defn add-space-to-items
|
||||||
;; Distributes the remainder space between the lines
|
;; Distributes the remainder space between the lines
|
||||||
[prop prop-min prop-max to-share items]
|
[prop prop-min prop-max to-share items]
|
||||||
(let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count)
|
(let [num-items (->> items (remove #(mth/close? (get % prop) (get % prop-max))) count)
|
||||||
per-line-target (/ to-share num-items)]
|
per-line-target (/ to-share num-items)]
|
||||||
(loop [current (first items)
|
|
||||||
items (rest items)
|
(loop [items (seq items)
|
||||||
remainder to-share
|
remainder to-share
|
||||||
result []]
|
result (transient [])]
|
||||||
(if (nil? current)
|
|
||||||
[result remainder]
|
(if (not items)
|
||||||
(let [cur-val (or (get current prop) (get current prop-min) 0)
|
[(persistent! result) remainder]
|
||||||
|
|
||||||
|
(let [current (first items)
|
||||||
|
cur-val (or (get current prop) (get current prop-min) 0)
|
||||||
max-val (get current prop-max)
|
max-val (get current prop-max)
|
||||||
cur-inc (if (> (+ cur-val per-line-target) max-val)
|
cur-inc (if (> (+ cur-val per-line-target) max-val)
|
||||||
(- max-val cur-val)
|
(- max-val cur-val)
|
||||||
per-line-target)
|
per-line-target)
|
||||||
current (assoc current prop (+ cur-val cur-inc))
|
current (assoc current prop (+ cur-val cur-inc))
|
||||||
remainder (- remainder cur-inc)
|
remainder (- remainder cur-inc)]
|
||||||
result (conj result current)]
|
(recur (next items) remainder (conj! result current)))))))
|
||||||
(recur (first items) (rest items) remainder result))))))
|
|
||||||
|
|
||||||
(defn distribute-space
|
(defn distribute-space
|
||||||
[prop prop-min prop-max min-value bound-value items]
|
[prop prop-min prop-max min-value bound-value items]
|
||||||
|
@ -200,36 +204,24 @@
|
||||||
(add-starts [total-width total-height num-lines [result base-p] layout-line]
|
(add-starts [total-width total-height num-lines [result base-p] layout-line]
|
||||||
(let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines)
|
(let [start-p (flp/get-start-line parent layout-bounds layout-line base-p total-width total-height num-lines)
|
||||||
next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)]
|
next-p (flp/get-next-line parent layout-bounds layout-line base-p total-width total-height num-lines)]
|
||||||
|
[(-> result (conj! (assoc layout-line :start-p start-p)))
|
||||||
|
next-p]))
|
||||||
|
|
||||||
[(conj result (assoc layout-line :start-p start-p))
|
(get-layout-width [{:keys [num-children]}]
|
||||||
next-p]))]
|
(let [num-gap (cond space-evenly? (inc num-children)
|
||||||
|
space-around? num-children
|
||||||
|
:else (dec num-children))]
|
||||||
|
(- layout-width (* layout-gap-col num-gap))))
|
||||||
|
|
||||||
|
(get-layout-height [{:keys [num-children]}]
|
||||||
|
(let [num-gap (cond space-evenly? (inc num-children)
|
||||||
|
space-around? num-children
|
||||||
|
:else (dec num-children))]
|
||||||
|
(- layout-height (* layout-gap-row num-gap))))]
|
||||||
|
|
||||||
(let [[total-min-width total-min-height total-max-width total-max-height]
|
(let [[total-min-width total-min-height total-max-width total-max-height]
|
||||||
(->> layout-lines (reduce add-ranges [0 0 0 0]))
|
(->> layout-lines (reduce add-ranges [0 0 0 0]))
|
||||||
|
|
||||||
get-layout-width (fn [{:keys [num-children]}]
|
|
||||||
(let [num-gap (cond
|
|
||||||
space-evenly?
|
|
||||||
(inc num-children)
|
|
||||||
|
|
||||||
space-around?
|
|
||||||
num-children
|
|
||||||
|
|
||||||
:else
|
|
||||||
(dec num-children))]
|
|
||||||
(- layout-width (* layout-gap-col num-gap))))
|
|
||||||
get-layout-height (fn [{:keys [num-children]}]
|
|
||||||
(let [num-gap (cond
|
|
||||||
space-evenly?
|
|
||||||
(inc num-children)
|
|
||||||
|
|
||||||
space-around?
|
|
||||||
num-children
|
|
||||||
|
|
||||||
:else
|
|
||||||
(dec num-children))]
|
|
||||||
(- layout-height (* layout-gap-row num-gap))))
|
|
||||||
|
|
||||||
num-lines (count layout-lines)
|
num-lines (count layout-lines)
|
||||||
|
|
||||||
;; When align-items is stretch we need to adjust the main axis size to grow for the full content
|
;; When align-items is stretch we need to adjust the main axis size to grow for the full content
|
||||||
|
@ -247,6 +239,7 @@
|
||||||
rest-layout-width (- layout-width (* (dec num-lines) layout-gap-col))
|
rest-layout-width (- layout-width (* (dec num-lines) layout-gap-col))
|
||||||
|
|
||||||
;; Distributes the space between the layout lines based on its max/min constraints
|
;; Distributes the space between the layout lines based on its max/min constraints
|
||||||
|
|
||||||
layout-lines
|
layout-lines
|
||||||
(cond->> layout-lines
|
(cond->> layout-lines
|
||||||
row?
|
row?
|
||||||
|
@ -267,14 +260,16 @@
|
||||||
(and row? (<= total-max-height rest-layout-height) (not auto-height?))
|
(and row? (<= total-max-height rest-layout-height) (not auto-height?))
|
||||||
(map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix)))
|
(map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix)))
|
||||||
|
|
||||||
(and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
|
|
||||||
(distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
|
|
||||||
|
|
||||||
(and col? (or (>= total-min-width rest-layout-width) auto-width?))
|
(and col? (or (>= total-min-width rest-layout-width) auto-width?))
|
||||||
(map #(assoc % :line-width (:line-min-width %)))
|
(map #(assoc % :line-width (:line-min-width %)))
|
||||||
|
|
||||||
(and col? (<= total-max-width rest-layout-width) (not auto-width?))
|
(and col? (<= total-max-width rest-layout-width) (not auto-width?))
|
||||||
(map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix)))
|
(map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))))
|
||||||
|
|
||||||
|
layout-lines
|
||||||
|
(cond->> layout-lines
|
||||||
|
(and row? (< total-min-height rest-layout-height total-max-height) (not auto-height?))
|
||||||
|
(distribute-space :line-height :line-min-height :line-max-height total-min-height rest-layout-height)
|
||||||
|
|
||||||
(and col? (< total-min-width rest-layout-width total-max-width) (not auto-width?))
|
(and col? (< total-min-width rest-layout-width total-max-width) (not auto-width?))
|
||||||
(distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width))
|
(distribute-space :line-width :line-min-width :line-max-width total-min-width rest-layout-width))
|
||||||
|
@ -286,19 +281,21 @@
|
||||||
(->> layout-lines
|
(->> layout-lines
|
||||||
(reduce
|
(reduce
|
||||||
(fn [[result rest-layout-height] {:keys [line-height] :as line}]
|
(fn [[result rest-layout-height] {:keys [line-height] :as line}]
|
||||||
[(conj result (assoc line :to-bound-height rest-layout-height))
|
[(conj! result (assoc line :to-bound-height rest-layout-height))
|
||||||
(- rest-layout-height line-height layout-gap-row)])
|
(- rest-layout-height line-height layout-gap-row)])
|
||||||
[[] layout-height])
|
[(transient []) layout-height])
|
||||||
(first))
|
(first)
|
||||||
|
(persistent!))
|
||||||
|
|
||||||
col?
|
col?
|
||||||
(->> layout-lines
|
(->> layout-lines
|
||||||
(reduce
|
(reduce
|
||||||
(fn [[result rest-layout-width] {:keys [line-width] :as line}]
|
(fn [[result rest-layout-width] {:keys [line-width] :as line}]
|
||||||
[(conj result (assoc line :to-bound-width rest-layout-width))
|
[(conj! result (assoc line :to-bound-width rest-layout-width))
|
||||||
(- rest-layout-width line-width layout-gap-col)])
|
(- rest-layout-width line-width layout-gap-col)])
|
||||||
[[] layout-width])
|
[(transient []) layout-width])
|
||||||
(first))
|
(first)
|
||||||
|
(persistent!))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
layout-lines)
|
layout-lines)
|
||||||
|
@ -307,7 +304,10 @@
|
||||||
|
|
||||||
base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)]
|
base-p (flp/get-base-line parent layout-bounds total-width total-height num-lines)]
|
||||||
|
|
||||||
(first (reduce (partial add-starts total-width total-height num-lines) [[] base-p] layout-lines))))))
|
(->> layout-lines
|
||||||
|
(reduce (partial add-starts total-width total-height num-lines) [(transient []) base-p])
|
||||||
|
(first)
|
||||||
|
(persistent!))))))
|
||||||
|
|
||||||
(defn add-line-spacing
|
(defn add-line-spacing
|
||||||
"Calculates the baseline for a flex layout"
|
"Calculates the baseline for a flex layout"
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.geom.bounds-map :as cgb]
|
||||||
|
[app.common.geom.modif-tree :as cgt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.common :as gco]
|
[app.common.geom.shapes.common :as gco]
|
||||||
[app.common.geom.shapes.constraints :as gct]
|
[app.common.geom.shapes.constraints :as gct]
|
||||||
|
@ -17,6 +19,7 @@
|
||||||
[app.common.geom.shapes.pixel-precision :as gpp]
|
[app.common.geom.shapes.pixel-precision :as gpp]
|
||||||
[app.common.geom.shapes.points :as gpo]
|
[app.common.geom.shapes.points :as gpo]
|
||||||
[app.common.geom.shapes.transforms :as gtr]
|
[app.common.geom.shapes.transforms :as gtr]
|
||||||
|
[app.common.geom.shapes.tree-seq :as cgst]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
@ -30,74 +33,6 @@
|
||||||
;; [(get-in objects [k :name]) v]))
|
;; [(get-in objects [k :name]) v]))
|
||||||
;; modif-tree))))
|
;; modif-tree))))
|
||||||
|
|
||||||
(defn- get-children-seq
|
|
||||||
"Given an id returns a sequence of its children"
|
|
||||||
[id objects]
|
|
||||||
|
|
||||||
(->> (tree-seq
|
|
||||||
#(d/not-empty? (dm/get-in objects [% :shapes]))
|
|
||||||
#(dm/get-in objects [% :shapes])
|
|
||||||
id)
|
|
||||||
(map #(get objects %))))
|
|
||||||
|
|
||||||
(defn- resolve-tree
|
|
||||||
"Given the ids that have changed search for layout roots to recalculate"
|
|
||||||
[ids objects]
|
|
||||||
(dm/assert! (or (nil? ids) (set? ids)))
|
|
||||||
|
|
||||||
(let [;; Finds the tree root for the current id
|
|
||||||
get-tree-root
|
|
||||||
(fn [id]
|
|
||||||
(loop [current id
|
|
||||||
result id]
|
|
||||||
(let [shape (get objects current)]
|
|
||||||
(if (or (not ^boolean shape) (= uuid/zero current))
|
|
||||||
result
|
|
||||||
(let [parent-id (dm/get-prop shape :parent-id)
|
|
||||||
parent (get objects parent-id)]
|
|
||||||
(cond
|
|
||||||
;; Frame found, but not layout we return the last layout found (or the id)
|
|
||||||
(and ^boolean (cph/frame-shape? parent)
|
|
||||||
(not ^boolean (ctl/any-layout? parent)))
|
|
||||||
result
|
|
||||||
|
|
||||||
;; Layout found. We continue upward but we mark this layout
|
|
||||||
(ctl/any-layout? parent)
|
|
||||||
(recur parent-id parent-id)
|
|
||||||
|
|
||||||
;; If group or boolean or other type of group we continue with the last result
|
|
||||||
:else
|
|
||||||
(recur parent-id result)))))))
|
|
||||||
|
|
||||||
;; Given some roots retrieves the minimum number of tree roots
|
|
||||||
search-common-roots
|
|
||||||
(fn [result id]
|
|
||||||
(if (= id uuid/zero)
|
|
||||||
result
|
|
||||||
(let [root (get-tree-root id)
|
|
||||||
|
|
||||||
;; Remove the children from the current root
|
|
||||||
result
|
|
||||||
(if ^boolean (cph/has-children? objects root)
|
|
||||||
(into #{} (remove (partial cph/is-child? objects root)) result)
|
|
||||||
result)
|
|
||||||
|
|
||||||
contains-parent?
|
|
||||||
(->> (cph/get-parent-ids objects root)
|
|
||||||
(some (partial contains? result)))]
|
|
||||||
|
|
||||||
(if (not contains-parent?)
|
|
||||||
(conj result root)
|
|
||||||
result))))
|
|
||||||
|
|
||||||
result
|
|
||||||
(->> (reduce search-common-roots #{} ids)
|
|
||||||
(mapcat #(get-children-seq % objects)))]
|
|
||||||
|
|
||||||
(if (contains? ids uuid/zero)
|
|
||||||
(cons (get objects uuid/zero) result)
|
|
||||||
result)))
|
|
||||||
|
|
||||||
(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 children objects bounds parent transformed-parent-bounds ignore-constraints]
|
[modif-tree children objects bounds parent transformed-parent-bounds ignore-constraints]
|
||||||
|
@ -108,85 +43,48 @@
|
||||||
modif-tree
|
modif-tree
|
||||||
|
|
||||||
(ctm/only-move? modifiers)
|
(ctm/only-move? modifiers)
|
||||||
(loop [modif-tree modif-tree
|
(reduce #(cgt/add-modifiers %1 %2 modifiers) modif-tree children)
|
||||||
children (seq children)]
|
|
||||||
(if-let [current (first children)]
|
|
||||||
(recur (update-in modif-tree [current :modifiers] ctm/add-modifiers modifiers)
|
|
||||||
(rest children))
|
|
||||||
modif-tree))
|
|
||||||
|
|
||||||
;; Check the constraints, then resize
|
;; Check the constraints, then resize
|
||||||
:else
|
:else
|
||||||
(let [parent-id (:id parent)
|
(let [parent-id (:id parent)
|
||||||
parent-bounds (gtr/transform-bounds @(get bounds parent-id) (ctm/select-parent modifiers))]
|
parent-bounds (gtr/transform-bounds @(get bounds parent-id) (ctm/select-parent modifiers))]
|
||||||
(loop [modif-tree modif-tree
|
|
||||||
children (seq children)]
|
|
||||||
(if (empty? children)
|
|
||||||
modif-tree
|
|
||||||
(let [child-id (first children)
|
|
||||||
child (get objects child-id)]
|
|
||||||
(if (some? child)
|
|
||||||
(let [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)))
|
|
||||||
(recur modif-tree (rest children))))))))))
|
|
||||||
|
|
||||||
(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 shape-id)]
|
|
||||||
|
|
||||||
(cond
|
|
||||||
(and (cph/mask-shape? shape) (seq children))
|
|
||||||
(get-group-bounds objects bounds modif-tree (-> children first))
|
|
||||||
|
|
||||||
(cph/group-shape? shape)
|
|
||||||
(let [;; Transform here to then calculate the bounds relative to the transform
|
|
||||||
current-bounds
|
|
||||||
(cond-> @(get bounds shape-id)
|
|
||||||
(not (ctm/empty? modifiers))
|
|
||||||
(gtr/transform-bounds modifiers))
|
|
||||||
|
|
||||||
children-bounds
|
|
||||||
(->> children
|
(->> children
|
||||||
(mapv #(get-group-bounds objects bounds modif-tree %)))]
|
(reduce
|
||||||
(gpo/merge-parent-coords-bounds children-bounds current-bounds))
|
(fn [modif-tree child-id]
|
||||||
|
(if-let [child (get objects child-id)]
|
||||||
|
(let [child-bounds @(get bounds child-id)
|
||||||
|
child-modifiers
|
||||||
|
(gct/calc-child-modifiers
|
||||||
|
parent child modifiers ignore-constraints
|
||||||
|
child-bounds
|
||||||
|
parent-bounds transformed-parent-bounds)]
|
||||||
|
|
||||||
:else
|
(cgt/add-modifiers modif-tree child-id child-modifiers))
|
||||||
(cond-> @(get bounds shape-id)
|
modif-tree))
|
||||||
(not (ctm/empty? modifiers))
|
modif-tree))))))
|
||||||
(gtr/transform-bounds modifiers)))))
|
|
||||||
|
|
||||||
(defn- set-flex-layout-modifiers
|
(defn- set-flex-layout-modifiers
|
||||||
[modif-tree children objects bounds parent transformed-parent-bounds]
|
[modif-tree children objects bounds parent transformed-parent-bounds]
|
||||||
|
|
||||||
(letfn [(apply-modifiers [child]
|
(letfn [(apply-modifiers [bounds child]
|
||||||
[(-> (get-group-bounds objects bounds modif-tree child)
|
[(-> @(get bounds (:id child))
|
||||||
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
||||||
child])
|
child])
|
||||||
|
|
||||||
(set-child-modifiers [[layout-line modif-tree] [child-bounds child]]
|
(set-child-modifiers [[layout-line modif-tree] [child-bounds child]]
|
||||||
(let [[modifiers layout-line]
|
(let [[modifiers layout-line]
|
||||||
(gcfl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line)
|
(gcfl/layout-child-modifiers parent transformed-parent-bounds child child-bounds layout-line)]
|
||||||
|
[layout-line (cgt/add-modifiers modif-tree (:id child) modifiers)]))]
|
||||||
|
|
||||||
modif-tree
|
(let [bounds (cgb/transform-bounds-map bounds objects modif-tree children)
|
||||||
(cond-> modif-tree
|
|
||||||
(d/not-empty? modifiers)
|
|
||||||
(update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))]
|
|
||||||
|
|
||||||
[layout-line modif-tree]))]
|
children
|
||||||
|
(->> children
|
||||||
(let [children (->> children
|
|
||||||
(keep (d/getf objects))
|
(keep (d/getf objects))
|
||||||
(remove :hidden)
|
(remove :hidden)
|
||||||
(remove gco/invalid-geometry?)
|
(remove gco/invalid-geometry?)
|
||||||
(map apply-modifiers))
|
(map (partial apply-modifiers bounds)))
|
||||||
|
|
||||||
layout-data (gcfl/calc-layout-data parent @transformed-parent-bounds children bounds objects)
|
layout-data (gcfl/calc-layout-data parent @transformed-parent-bounds children bounds objects)
|
||||||
children (into [] (cond-> children (not (:reverse? layout-data)) reverse))
|
children (into [] (cond-> children (not (:reverse? layout-data)) reverse))
|
||||||
|
@ -209,24 +107,21 @@
|
||||||
(defn- set-grid-layout-modifiers
|
(defn- set-grid-layout-modifiers
|
||||||
[modif-tree objects bounds parent transformed-parent-bounds]
|
[modif-tree objects bounds parent transformed-parent-bounds]
|
||||||
|
|
||||||
(letfn [(apply-modifiers [child]
|
(letfn [(apply-modifiers [bounds child]
|
||||||
[(-> (get-group-bounds objects bounds modif-tree child)
|
[(-> @(get bounds (:id child))
|
||||||
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
(gpo/parent-coords-bounds @transformed-parent-bounds))
|
||||||
child])
|
child])
|
||||||
|
|
||||||
(set-child-modifiers [modif-tree grid-data cell-data [child-bounds child]]
|
(set-child-modifiers [modif-tree grid-data cell-data [child-bounds child]]
|
||||||
(let [modifiers
|
(let [modifiers
|
||||||
(gcgl/child-modifiers parent transformed-parent-bounds child child-bounds grid-data cell-data)
|
(gcgl/child-modifiers parent transformed-parent-bounds child child-bounds grid-data cell-data)]
|
||||||
|
(cgt/add-modifiers modif-tree (:id child) modifiers)))]
|
||||||
|
|
||||||
modif-tree
|
(let [bounds (cgb/transform-bounds-map bounds objects modif-tree (:shapes parent))
|
||||||
(cond-> modif-tree
|
|
||||||
(d/not-empty? modifiers)
|
children
|
||||||
(update-in [(:id child) :modifiers] ctm/add-modifiers modifiers))]
|
(->> (cph/get-immediate-children objects (:id parent) {:remove-hidden true})
|
||||||
modif-tree))]
|
(map (partial apply-modifiers bounds)))
|
||||||
(let [children (->> (cph/get-immediate-children objects (:id parent))
|
|
||||||
(remove :hidden)
|
|
||||||
(remove gco/invalid-geometry?)
|
|
||||||
(map apply-modifiers))
|
|
||||||
grid-data (gcgl/calc-layout-data parent @transformed-parent-bounds children bounds objects)]
|
grid-data (gcgl/calc-layout-data parent @transformed-parent-bounds children bounds objects)]
|
||||||
(loop [modif-tree modif-tree
|
(loop [modif-tree modif-tree
|
||||||
bound+child (first children)
|
bound+child (first children)
|
||||||
|
@ -239,6 +134,71 @@
|
||||||
(recur modif-tree (first pending) (rest pending)))
|
(recur modif-tree (first pending) (rest pending)))
|
||||||
modif-tree)))))
|
modif-tree)))))
|
||||||
|
|
||||||
|
(defn- set-modifiers-constraints
|
||||||
|
"Propagate modifiers to its children"
|
||||||
|
[objects bounds ignore-constraints modif-tree parent]
|
||||||
|
(let [parent-id (:id parent)
|
||||||
|
children (:shapes parent)
|
||||||
|
root? (= uuid/zero parent-id)
|
||||||
|
modifiers (-> (dm/get-in modif-tree [parent-id :modifiers])
|
||||||
|
(ctm/select-geometry))
|
||||||
|
has-modifiers? (ctm/child-modifiers? modifiers)
|
||||||
|
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
||||||
|
transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))]
|
||||||
|
|
||||||
|
(cond-> modif-tree
|
||||||
|
(and has-modifiers? parent? (not root?))
|
||||||
|
(set-children-modifiers children objects bounds parent transformed-parent-bounds ignore-constraints))))
|
||||||
|
|
||||||
|
(defn- set-modifiers-layout
|
||||||
|
"Propagate modifiers to its children"
|
||||||
|
([objects bounds ignore-constraints parent]
|
||||||
|
(set-modifiers-layout objects bounds ignore-constraints {} parent))
|
||||||
|
([objects bounds ignore-constraints modif-tree 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)
|
||||||
|
flex-layout? (ctl/flex-layout? parent)
|
||||||
|
grid-layout? (ctl/grid-layout? parent)
|
||||||
|
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
||||||
|
|
||||||
|
transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))
|
||||||
|
|
||||||
|
children-modifiers
|
||||||
|
(if (or flex-layout? grid-layout?)
|
||||||
|
(->> (:shapes parent)
|
||||||
|
(filter #(ctl/layout-absolute? objects %)))
|
||||||
|
(:shapes parent))
|
||||||
|
|
||||||
|
children-layout
|
||||||
|
(when (or flex-layout? grid-layout?)
|
||||||
|
(->> (:shapes parent)
|
||||||
|
(remove #(ctl/layout-absolute? objects %))))]
|
||||||
|
|
||||||
|
(cond-> modif-tree
|
||||||
|
(and has-modifiers? parent? (not root?))
|
||||||
|
(set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints)
|
||||||
|
|
||||||
|
flex-layout?
|
||||||
|
(set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)
|
||||||
|
|
||||||
|
grid-layout?
|
||||||
|
(set-grid-layout-modifiers objects bounds parent transformed-parent-bounds)))))
|
||||||
|
|
||||||
|
(defn propagate-modifiers-constraints
|
||||||
|
([objects bounds ignore-constraints shapes]
|
||||||
|
(propagate-modifiers-constraints objects bounds ignore-constraints {} shapes))
|
||||||
|
([objects bounds ignore-constraints modif-tree shapes]
|
||||||
|
(reduce #(set-modifiers-constraints objects bounds ignore-constraints %1 %2) modif-tree shapes)))
|
||||||
|
|
||||||
|
(defn propagate-modifiers-layouts
|
||||||
|
([objects bounds ignore-constraints shapes]
|
||||||
|
(propagate-modifiers-layouts objects bounds ignore-constraints {} shapes))
|
||||||
|
([objects bounds ignore-constraints modif-tree shapes]
|
||||||
|
(reduce #(set-modifiers-layout objects bounds ignore-constraints %1 %2) modif-tree shapes)))
|
||||||
|
|
||||||
(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 bounds parent]
|
[objects bounds parent]
|
||||||
|
@ -248,14 +208,16 @@
|
||||||
set-parent-auto-width
|
set-parent-auto-width
|
||||||
(fn [modifiers auto-width]
|
(fn [modifiers auto-width]
|
||||||
(let [origin (gpo/origin @parent-bounds)
|
(let [origin (gpo/origin @parent-bounds)
|
||||||
scale-width (/ auto-width (gpo/width-points @parent-bounds))]
|
current-width (gpo/width-points @parent-bounds)
|
||||||
|
scale-width (/ auto-width current-width)]
|
||||||
(-> modifiers
|
(-> modifiers
|
||||||
(ctm/resize (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
|
(ctm/resize (gpt/point scale-width 1) origin (:transform parent) (:transform-inverse parent)))))
|
||||||
|
|
||||||
set-parent-auto-height
|
set-parent-auto-height
|
||||||
(fn [modifiers auto-height]
|
(fn [modifiers auto-height]
|
||||||
(let [origin (gpo/origin @parent-bounds)
|
(let [origin (gpo/origin @parent-bounds)
|
||||||
scale-height (/ auto-height (gpo/height-points @parent-bounds))]
|
current-height (gpo/height-points @parent-bounds)
|
||||||
|
scale-height (/ auto-height current-height)]
|
||||||
(-> modifiers
|
(-> modifiers
|
||||||
(ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))
|
(ctm/resize (gpt/point 1 scale-height) origin (:transform parent) (:transform-inverse parent)))))
|
||||||
|
|
||||||
|
@ -264,7 +226,7 @@
|
||||||
(remove gco/invalid-geometry?))
|
(remove gco/invalid-geometry?))
|
||||||
|
|
||||||
content-bounds
|
content-bounds
|
||||||
(when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent)))
|
(when (and (d/not-empty? children) (ctl/auto? parent))
|
||||||
(cond
|
(cond
|
||||||
(ctl/flex-layout? parent)
|
(ctl/flex-layout? parent)
|
||||||
(gcfl/layout-content-bounds bounds parent children objects)
|
(gcfl/layout-content-bounds bounds parent children objects)
|
||||||
|
@ -285,189 +247,54 @@
|
||||||
(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-constraints
|
(defn find-auto-layouts
|
||||||
"Propagate modifiers to its children"
|
[objects shapes]
|
||||||
[objects bounds ignore-constraints modif-tree parent]
|
|
||||||
(let [parent-id (:id parent)
|
|
||||||
children (:shapes parent)
|
|
||||||
root? (= uuid/zero parent-id)
|
|
||||||
modifiers (-> (dm/get-in modif-tree [parent-id :modifiers])
|
|
||||||
(ctm/select-geometry))
|
|
||||||
has-modifiers? (ctm/child-modifiers? modifiers)
|
|
||||||
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
|
||||||
transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))]
|
|
||||||
|
|
||||||
(cond-> modif-tree
|
|
||||||
(and has-modifiers? parent? (not root?))
|
|
||||||
(set-children-modifiers children objects bounds parent transformed-parent-bounds ignore-constraints))))
|
|
||||||
|
|
||||||
(defn- propagate-modifiers-layout
|
|
||||||
"Propagate modifiers to its children"
|
|
||||||
[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)
|
|
||||||
flex-layout? (ctl/flex-layout? parent)
|
|
||||||
grid-layout? (ctl/grid-layout? parent)
|
|
||||||
auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent))
|
|
||||||
fill-with-grid? (and (ctl/grid-layout? objects (:parent-id parent))
|
|
||||||
(or (ctl/fill-width? parent) (ctl/fill-height? parent)))
|
|
||||||
parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent))
|
|
||||||
|
|
||||||
transformed-parent-bounds (delay (gtr/transform-bounds @(get bounds parent-id) modifiers))
|
|
||||||
|
|
||||||
children-modifiers
|
|
||||||
(if (or flex-layout? grid-layout?)
|
|
||||||
(->> (:shapes parent)
|
|
||||||
(filter #(ctl/layout-absolute? objects %)))
|
|
||||||
(:shapes parent))
|
|
||||||
|
|
||||||
children-layout
|
|
||||||
(when (or flex-layout? grid-layout?)
|
|
||||||
(->> (:shapes parent)
|
|
||||||
(remove #(ctl/layout-absolute? objects %))))]
|
|
||||||
|
|
||||||
[(cond-> modif-tree
|
|
||||||
(and has-modifiers? parent? (not root?))
|
|
||||||
(set-children-modifiers children-modifiers objects bounds parent transformed-parent-bounds ignore-constraints)
|
|
||||||
|
|
||||||
flex-layout?
|
|
||||||
(set-flex-layout-modifiers children-layout objects bounds parent transformed-parent-bounds)
|
|
||||||
|
|
||||||
grid-layout?
|
|
||||||
(set-grid-layout-modifiers objects bounds parent transformed-parent-bounds))
|
|
||||||
|
|
||||||
|
(letfn [(mk-check-auto-layout [objects]
|
||||||
|
(fn [shape]
|
||||||
;; 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
|
||||||
;; also if the child is fill width/height inside a grid layout
|
;; also if the child is fill width/height inside a grid layout
|
||||||
(cond-> autolayouts (or auto? fill-with-grid?) (conj (:id parent)))]))
|
(when (or (ctl/auto? shape)
|
||||||
|
(and (ctl/grid-layout? objects (:parent-id shape)) (ctl/fill? shape)))
|
||||||
(defn- apply-structure-modifiers
|
(:id shape))))]
|
||||||
[objects modif-tree]
|
(into (d/ordered-set)
|
||||||
(letfn [(update-children-structure-modifiers
|
(keep (mk-check-auto-layout objects))
|
||||||
[objects ids modifiers]
|
shapes)))
|
||||||
(reduce #(update %1 %2 ctm/apply-structure-modifiers modifiers) objects ids))
|
|
||||||
|
|
||||||
(apply-shape [objects [id {:keys [modifiers]}]]
|
|
||||||
(cond-> objects
|
|
||||||
(ctm/has-structure? modifiers)
|
|
||||||
(update id ctm/apply-structure-modifiers modifiers)
|
|
||||||
|
|
||||||
(and (ctm/has-structure? modifiers)
|
|
||||||
(ctm/has-structure-child? modifiers))
|
|
||||||
(update-children-structure-modifiers
|
|
||||||
(cph/get-children-ids objects id)
|
|
||||||
(ctm/select-child-structre-modifiers modifiers))))]
|
|
||||||
(reduce apply-shape objects modif-tree)))
|
|
||||||
|
|
||||||
(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 transform-bounds
|
|
||||||
([bounds objects modif-tree]
|
|
||||||
(transform-bounds bounds objects modif-tree (->> (keys modif-tree) (map #(get objects %)))))
|
|
||||||
([bounds objects modif-tree tree-seq]
|
|
||||||
|
|
||||||
(loop [result bounds
|
|
||||||
shapes (reverse tree-seq)]
|
|
||||||
(if (empty? shapes)
|
|
||||||
result
|
|
||||||
|
|
||||||
(let [shape (first shapes)
|
|
||||||
new-bounds (delay (get-group-bounds objects bounds modif-tree shape))
|
|
||||||
result (assoc result (:id shape) new-bounds)]
|
|
||||||
(recur result (rest shapes)))))))
|
|
||||||
|
|
||||||
(defn reflow-layout
|
|
||||||
[objects old-modif-tree bounds ignore-constraints id]
|
|
||||||
|
|
||||||
(let [tree-seq (get-children-seq id objects)
|
|
||||||
|
|
||||||
[modif-tree _]
|
|
||||||
(reduce
|
|
||||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
|
|
||||||
tree-seq)
|
|
||||||
|
|
||||||
bounds (transform-bounds bounds objects modif-tree tree-seq)
|
|
||||||
|
|
||||||
modif-tree (merge-modif-tree old-modif-tree modif-tree)]
|
|
||||||
[modif-tree bounds]))
|
|
||||||
|
|
||||||
(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 bounds ignore-constraints]
|
[modif-tree sizing-auto-layouts objects bounds ignore-constraints]
|
||||||
(let [;; Step-1 resize the auto-width/height. Reflow the parents if they are also auto-width/height
|
|
||||||
[modif-tree bounds to-reflow]
|
|
||||||
(loop [modif-tree modif-tree
|
|
||||||
bounds bounds
|
|
||||||
sizing-auto-layouts (reverse sizing-auto-layouts)
|
|
||||||
to-reflow #{}]
|
|
||||||
(if-let [current (first sizing-auto-layouts)]
|
|
||||||
(let [parent-base (get objects current)
|
|
||||||
|
|
||||||
|
(let [calculate-modifiers
|
||||||
|
(fn [[modif-tree bounds] layout-id]
|
||||||
|
(let [layout (get objects layout-id)
|
||||||
|
auto-modifiers (calc-auto-modifiers objects bounds layout)]
|
||||||
|
|
||||||
|
(if (and (ctm/empty? auto-modifiers) (not (ctl/grid-layout? layout)))
|
||||||
[modif-tree bounds]
|
[modif-tree bounds]
|
||||||
(if (contains? to-reflow current)
|
|
||||||
(reflow-layout objects modif-tree bounds ignore-constraints current)
|
|
||||||
[modif-tree bounds])
|
|
||||||
|
|
||||||
auto-resize-modifiers
|
(let [from-layout
|
||||||
(calc-auto-modifiers objects bounds parent-base)
|
(->> (cph/get-parent-ids objects layout-id)
|
||||||
|
(d/seek sizing-auto-layouts))
|
||||||
|
|
||||||
to-reflow
|
shapes
|
||||||
(cond-> to-reflow
|
(if from-layout
|
||||||
(contains? to-reflow current)
|
(cgst/resolve-subtree from-layout layout-id objects)
|
||||||
(disj current))]
|
(cgst/resolve-tree #{layout-id} objects))
|
||||||
|
|
||||||
(if (and (ctm/empty? auto-resize-modifiers)
|
auto-modif-tree {layout-id {:modifiers auto-modifiers}}
|
||||||
(not (ctl/grid-layout? objects (:parent-id parent-base))))
|
auto-modif-tree (propagate-modifiers-layouts objects bounds ignore-constraints auto-modif-tree shapes)
|
||||||
(recur modif-tree
|
|
||||||
bounds
|
|
||||||
(rest sizing-auto-layouts)
|
|
||||||
to-reflow)
|
|
||||||
|
|
||||||
(let [resize-modif-tree {current {:modifiers auto-resize-modifiers}}
|
bounds (cgb/transform-bounds-map bounds objects auto-modif-tree)
|
||||||
|
modif-tree (cgt/merge-modif-tree modif-tree auto-modif-tree)]
|
||||||
tree-seq (get-children-seq current objects)
|
[modif-tree bounds]))))]
|
||||||
|
(->> sizing-auto-layouts
|
||||||
[resize-modif-tree _]
|
(reverse)
|
||||||
(reduce
|
(reduce calculate-modifiers [modif-tree bounds])
|
||||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [resize-modif-tree #{}]
|
(first))))
|
||||||
tree-seq)
|
|
||||||
|
|
||||||
bounds (transform-bounds bounds objects resize-modif-tree tree-seq)
|
|
||||||
|
|
||||||
modif-tree (merge-modif-tree modif-tree resize-modif-tree)
|
|
||||||
|
|
||||||
to-reflow
|
|
||||||
(cond-> to-reflow
|
|
||||||
(and (ctl/any-layout-descent? objects parent-base)
|
|
||||||
(not= uuid/zero (:frame-id parent-base)))
|
|
||||||
(conj (:frame-id parent-base)))]
|
|
||||||
(recur modif-tree
|
|
||||||
bounds
|
|
||||||
(rest sizing-auto-layouts)
|
|
||||||
to-reflow))))
|
|
||||||
[modif-tree bounds to-reflow]))
|
|
||||||
|
|
||||||
;; Step-2: After resizing we still need to reflow the layout parents that are not auto-width/height
|
|
||||||
|
|
||||||
tree-seq (resolve-tree to-reflow objects)
|
|
||||||
|
|
||||||
[reflow-modif-tree _]
|
|
||||||
(reduce
|
|
||||||
#(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}]
|
|
||||||
tree-seq)
|
|
||||||
|
|
||||||
result (merge-modif-tree modif-tree reflow-modif-tree)]
|
|
||||||
|
|
||||||
result))
|
|
||||||
|
|
||||||
(defn set-objects-modifiers
|
(defn set-objects-modifiers
|
||||||
|
"Applies recursively the modifiers and calculate the layouts and constraints for all the items to be placed correctly"
|
||||||
([modif-tree objects]
|
([modif-tree objects]
|
||||||
(set-objects-modifiers modif-tree objects nil))
|
(set-objects-modifiers modif-tree objects nil))
|
||||||
|
|
||||||
|
@ -476,43 +303,59 @@
|
||||||
|
|
||||||
([old-modif-tree modif-tree objects
|
([old-modif-tree modif-tree objects
|
||||||
{:keys [ignore-constraints snap-pixel? snap-precision snap-ignore-axis]
|
{:keys [ignore-constraints snap-pixel? snap-precision snap-ignore-axis]
|
||||||
:or {ignore-constraints false snap-pixel? false snap-precision 1 snap-ignore-axis nil}}]
|
:or {ignore-constraints false
|
||||||
|
snap-pixel? false
|
||||||
|
snap-precision 1
|
||||||
|
snap-ignore-axis nil}}]
|
||||||
|
|
||||||
(let [objects (-> objects
|
(let [;; Apply structure modifiers. Things that are not related to geometry
|
||||||
|
objects
|
||||||
|
(-> objects
|
||||||
(cond-> (some? old-modif-tree)
|
(cond-> (some? old-modif-tree)
|
||||||
(apply-structure-modifiers old-modif-tree))
|
(cgt/apply-structure-modifiers old-modif-tree))
|
||||||
(apply-structure-modifiers modif-tree))
|
(cgt/apply-structure-modifiers modif-tree))
|
||||||
|
|
||||||
|
;; Creates the sequence of shapes with the shapes that are modified
|
||||||
|
shapes-tree
|
||||||
|
(cgst/resolve-tree (-> modif-tree keys set) objects)
|
||||||
|
|
||||||
|
bounds-map
|
||||||
|
(cond-> (cgb/objects->bounds-map objects)
|
||||||
|
(some? old-modif-tree)
|
||||||
|
(cgb/transform-bounds-map objects old-modif-tree))
|
||||||
|
|
||||||
|
;; Round the transforms if the snap-to-pixel is active
|
||||||
modif-tree
|
modif-tree
|
||||||
(cond-> modif-tree
|
(cond-> modif-tree
|
||||||
snap-pixel? (gpp/adjust-pixel-precision objects snap-precision snap-ignore-axis))
|
snap-pixel?
|
||||||
|
(gpp/adjust-pixel-precision objects snap-precision snap-ignore-axis))
|
||||||
|
|
||||||
bounds (d/lazy-map (keys objects) #(gco/shape->points (get objects %)))
|
;; Propagates the modifiers to the normal shapes with constraints
|
||||||
bounds (cond-> bounds
|
modif-tree
|
||||||
(some? old-modif-tree)
|
(propagate-modifiers-constraints objects bounds-map ignore-constraints modif-tree shapes-tree)
|
||||||
(transform-bounds objects old-modif-tree))
|
|
||||||
|
|
||||||
shapes-tree (resolve-tree (-> modif-tree keys set) objects)
|
bounds-map
|
||||||
|
(cgb/transform-bounds-map bounds-map objects modif-tree)
|
||||||
|
|
||||||
;; Calculate the input transformation and constraints
|
modif-tree-layout
|
||||||
modif-tree (reduce #(propagate-modifiers-constraints objects bounds ignore-constraints %1 %2) modif-tree shapes-tree)
|
(propagate-modifiers-layouts objects bounds-map ignore-constraints shapes-tree)
|
||||||
bounds (transform-bounds bounds objects modif-tree shapes-tree)
|
|
||||||
|
|
||||||
[modif-tree-layout sizing-auto-layouts]
|
|
||||||
(reduce #(propagate-modifiers-layout objects bounds ignore-constraints %1 %2) [{} #{}] shapes-tree)
|
|
||||||
|
|
||||||
modif-tree (merge-modif-tree modif-tree modif-tree-layout)
|
|
||||||
|
|
||||||
;; Calculate hug layouts positions
|
|
||||||
bounds (transform-bounds bounds objects modif-tree-layout shapes-tree)
|
|
||||||
|
|
||||||
modif-tree
|
modif-tree
|
||||||
(-> modif-tree
|
(cgt/merge-modif-tree modif-tree modif-tree-layout)
|
||||||
(sizing-auto-modifiers sizing-auto-layouts objects bounds ignore-constraints))
|
|
||||||
|
;; Calculate hug layouts positions
|
||||||
|
bounds-map
|
||||||
|
(cgb/transform-bounds-map bounds-map objects modif-tree-layout)
|
||||||
|
|
||||||
|
;; Find layouts with auto width/height
|
||||||
|
sizing-auto-layouts (find-auto-layouts objects shapes-tree)
|
||||||
|
|
||||||
|
modif-tree
|
||||||
|
(sizing-auto-modifiers modif-tree sizing-auto-layouts objects bounds-map ignore-constraints)
|
||||||
|
|
||||||
modif-tree
|
modif-tree
|
||||||
(if old-modif-tree
|
(if old-modif-tree
|
||||||
(merge-modif-tree old-modif-tree modif-tree)
|
(cgt/merge-modif-tree old-modif-tree modif-tree)
|
||||||
modif-tree)]
|
modif-tree)]
|
||||||
|
|
||||||
;;#?(:cljs
|
;;#?(:cljs
|
||||||
|
|
|
@ -116,6 +116,9 @@
|
||||||
(if (empty? child-bounds)
|
(if (empty? child-bounds)
|
||||||
parent-bounds
|
parent-bounds
|
||||||
|
|
||||||
|
(if (and (axis-aligned? child-bounds) (axis-aligned? parent-bounds))
|
||||||
|
child-bounds
|
||||||
|
|
||||||
(let [rh [p1 p2]
|
(let [rh [p1 p2]
|
||||||
rv [p1 p4]
|
rv [p1 p4]
|
||||||
|
|
||||||
|
@ -153,8 +156,7 @@
|
||||||
i2 (gsi/line-line-intersect minv-start minv-end maxh-start maxh-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)
|
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)]
|
i4 (gsi/line-line-intersect maxv-start maxv-end minh-start minh-end)]
|
||||||
|
[i1 i2 i3 i4]))))
|
||||||
[i1 i2 i3 i4])))
|
|
||||||
|
|
||||||
(defn merge-parent-coords-bounds
|
(defn merge-parent-coords-bounds
|
||||||
[bounds parent-bounds]
|
[bounds parent-bounds]
|
||||||
|
|
93
common/src/app/common/geom/shapes/tree_seq.cljc
Normal file
93
common/src/app/common/geom/shapes/tree_seq.cljc
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.common.geom.shapes.tree-seq
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.geom.shapes.min-size-layout]
|
||||||
|
[app.common.pages.helpers :as cph]
|
||||||
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.common.uuid :as uuid]))
|
||||||
|
|
||||||
|
(defn get-children-seq
|
||||||
|
"Given an id returns a sequence of its children"
|
||||||
|
[id objects]
|
||||||
|
(->> (tree-seq
|
||||||
|
#(d/not-empty? (dm/get-in objects [% :shapes]))
|
||||||
|
#(dm/get-in objects [% :shapes])
|
||||||
|
id)
|
||||||
|
(map #(get objects %))))
|
||||||
|
|
||||||
|
;; Finds the tree root for the current id
|
||||||
|
(defn get-reflow-root
|
||||||
|
([id objects]
|
||||||
|
(get-reflow-root id id objects))
|
||||||
|
|
||||||
|
([current last-root objects]
|
||||||
|
(let [shape (get objects current)]
|
||||||
|
(if (or (not ^boolean shape) (= uuid/zero current))
|
||||||
|
last-root
|
||||||
|
(let [parent-id (dm/get-prop shape :parent-id)
|
||||||
|
parent (get objects parent-id)]
|
||||||
|
(cond
|
||||||
|
;; Frame found, but not layout we return the last layout found (or the id)
|
||||||
|
(and ^boolean (cph/frame-shape? parent)
|
||||||
|
(not ^boolean (ctl/any-layout? parent)))
|
||||||
|
last-root
|
||||||
|
|
||||||
|
;; Auto-Layout found. We continue upward but we mark this layout
|
||||||
|
(and (ctl/any-layout? parent) (ctl/auto? parent))
|
||||||
|
(recur parent-id parent-id objects)
|
||||||
|
|
||||||
|
(ctl/any-layout? parent)
|
||||||
|
parent-id
|
||||||
|
|
||||||
|
;; If group or boolean or other type of group we continue with the last result
|
||||||
|
:else
|
||||||
|
(recur parent-id last-root objects)))))))
|
||||||
|
|
||||||
|
;; Given some roots retrieves the minimum number of tree roots
|
||||||
|
(defn search-common-roots
|
||||||
|
[ids objects]
|
||||||
|
(let [find-root
|
||||||
|
(fn [roots id]
|
||||||
|
(if (= id uuid/zero)
|
||||||
|
roots
|
||||||
|
(let [root (get-reflow-root id objects)
|
||||||
|
;; Remove the children from the current root
|
||||||
|
roots
|
||||||
|
(if ^boolean (cph/has-children? objects root)
|
||||||
|
(into #{} (remove (partial cph/is-child? objects root)) roots)
|
||||||
|
roots)
|
||||||
|
|
||||||
|
contains-parent?
|
||||||
|
(->> (cph/get-parent-ids objects root)
|
||||||
|
(some (partial contains? roots)))]
|
||||||
|
|
||||||
|
(cond-> roots
|
||||||
|
(not contains-parent?)
|
||||||
|
(conj root)))))]
|
||||||
|
(reduce find-root #{} ids)))
|
||||||
|
|
||||||
|
(defn resolve-tree
|
||||||
|
"Given the ids that have changed search for layout roots to recalculate"
|
||||||
|
[ids objects]
|
||||||
|
(dm/assert! (or (nil? ids) (set? ids)))
|
||||||
|
|
||||||
|
(let [child-seq
|
||||||
|
(->> (search-common-roots ids objects)
|
||||||
|
(mapcat #(get-children-seq % objects)))]
|
||||||
|
|
||||||
|
(if (contains? ids uuid/zero)
|
||||||
|
(cons (get objects uuid/zero) child-seq)
|
||||||
|
child-seq)))
|
||||||
|
|
||||||
|
(defn resolve-subtree
|
||||||
|
"Resolves the subtree but only partialy from-to the parameters"
|
||||||
|
[from-id to-id objects]
|
||||||
|
(->> (get-children-seq from-id objects)
|
||||||
|
(d/take-until #(= (:id %) to-id))))
|
|
@ -68,9 +68,11 @@
|
||||||
(= :bool (dm/get-prop shape :type))))
|
(= :bool (dm/get-prop shape :type))))
|
||||||
|
|
||||||
(defn group-like-shape?
|
(defn group-like-shape?
|
||||||
[shape]
|
([objects id]
|
||||||
|
(group-like-shape? (get objects id)))
|
||||||
|
([shape]
|
||||||
(or ^boolean (group-shape? shape)
|
(or ^boolean (group-shape? shape)
|
||||||
^boolean (bool-shape? shape)))
|
^boolean (bool-shape? shape))))
|
||||||
|
|
||||||
(defn text-shape?
|
(defn text-shape?
|
||||||
[shape]
|
[shape]
|
||||||
|
@ -160,6 +162,13 @@
|
||||||
(recur (conj result parent-id) parent-id)
|
(recur (conj result parent-id) parent-id)
|
||||||
result))))
|
result))))
|
||||||
|
|
||||||
|
(defn get-parent-ids-seq
|
||||||
|
"Returns a vector of parents of the specified shape."
|
||||||
|
[objects shape-id]
|
||||||
|
(let [parent-id (get-parent-id objects shape-id)]
|
||||||
|
(when (and (some? parent-id) (not= parent-id shape-id))
|
||||||
|
(lazy-seq (cons parent-id (get-parent-ids-seq objects parent-id))))))
|
||||||
|
|
||||||
(defn get-parents
|
(defn get-parents
|
||||||
"Returns a vector of parents of the specified shape."
|
"Returns a vector of parents of the specified shape."
|
||||||
[objects shape-id]
|
[objects shape-id]
|
||||||
|
@ -169,6 +178,17 @@
|
||||||
(recur (conj result (get objects parent-id)) parent-id)
|
(recur (conj result (get objects parent-id)) parent-id)
|
||||||
result))))
|
result))))
|
||||||
|
|
||||||
|
(defn get-parent-seq
|
||||||
|
"Returns a vector of parents of the specified shape."
|
||||||
|
([objects shape-id]
|
||||||
|
(get-parent-seq objects (get objects shape-id) shape-id))
|
||||||
|
|
||||||
|
([objects shape shape-id]
|
||||||
|
(let [parent-id (dm/get-prop shape :parent-id)
|
||||||
|
parent (get objects parent-id)]
|
||||||
|
(when (and (some? parent) (not= parent-id shape-id))
|
||||||
|
(lazy-seq (cons parent (get-parent-seq objects parent parent-id)))))))
|
||||||
|
|
||||||
(defn get-parents-with-self
|
(defn get-parents-with-self
|
||||||
[objects id]
|
[objects id]
|
||||||
(let [lookup (d/getf objects)]
|
(let [lookup (d/getf objects)]
|
||||||
|
|
|
@ -277,6 +277,12 @@
|
||||||
([child]
|
([child]
|
||||||
(= :fill (:layout-item-v-sizing child))))
|
(= :fill (:layout-item-v-sizing child))))
|
||||||
|
|
||||||
|
(defn fill?
|
||||||
|
([objects id]
|
||||||
|
(or (fill-height? objects id) (fill-width? objects id)))
|
||||||
|
([shape]
|
||||||
|
(or (fill-height? shape) (fill-width? shape))))
|
||||||
|
|
||||||
(defn auto-width?
|
(defn auto-width?
|
||||||
([objects id]
|
([objects id]
|
||||||
(= :auto (dm/get-in objects [id :layout-item-h-sizing])))
|
(= :auto (dm/get-in objects [id :layout-item-h-sizing])))
|
||||||
|
@ -289,6 +295,12 @@
|
||||||
([child]
|
([child]
|
||||||
(= :auto (:layout-item-v-sizing child))))
|
(= :auto (:layout-item-v-sizing child))))
|
||||||
|
|
||||||
|
(defn auto?
|
||||||
|
([objects id]
|
||||||
|
(or (auto-height? objects id) (auto-width? objects id)))
|
||||||
|
([shape]
|
||||||
|
(or (auto-height? shape) (auto-width? shape))))
|
||||||
|
|
||||||
(defn col?
|
(defn col?
|
||||||
([objects id]
|
([objects id]
|
||||||
(col? (get objects id)))
|
(col? (get objects id)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue