diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index 4a187191b..3c77f4a6f 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -135,10 +135,10 @@ (letfn [(apply-modifiers [modif-tree child] (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] (cond-> child - (some? modifiers) + (and (not (cph/group-shape? child)) (some? modifiers)) (gtr/transform-shape modifiers) - (cph/group-like-shape? child) + (cph/group-shape? child) (gtr/apply-group-modifiers objects modif-tree)))) (set-child-modifiers [parent [layout-line modif-tree] child] @@ -152,7 +152,7 @@ [layout-line modif-tree]))] - (let [children (map (d/getf objects) (:shapes parent)) + (let [children (map (d/getf objects) (:shapes parent)) children (->> children (map (partial apply-modifiers modif-tree))) layout-data (gcl/calc-layout-data parent children) children (into [] (cond-> children (:reverse? layout-data) reverse)) @@ -173,119 +173,136 @@ modif-tree))))) -(defn- set-auto-modifiers +(defn- calc-auto-modifiers "Calculates the modifiers to adjust the bounds for auto-width/auto-height shapes" - [modif-tree objects parent] - (letfn [(apply-modifiers - [child] - (let [modifiers (dm/get-in modif-tree [(:id child) :modifiers])] - (cond-> child - (some? modifiers) - (gtr/transform-shape modifiers) - - (and (some? modifiers) (cph/group-like-shape? child)) - (gtr/apply-group-modifiers objects modif-tree)))) - - (set-parent-auto-width - [modifiers parent auto-width] + [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))))) (set-parent-auto-height - [modifiers 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)))))] - (let [modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) - children (->> parent - :shapes - (map (comp apply-modifiers (d/getf objects)))) + (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)) + (gcl/layout-content-bounds parent children))] - modifiers - (cond-> modifiers - (and (some? auto-width) (ctl/auto-width? parent)) - (set-parent-auto-width parent auto-width) + (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 parent auto-height))] - - (assoc-in modif-tree [(:id parent) :modifiers] modifiers)))) + (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 recalculate] parent] + [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]) transformed-parent (gtr/transform-shape parent modifiers) has-modifiers? (ctm/child-modifiers? modifiers) - is-layout? (ctl/layout? parent) - is-auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) - is-parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) + layout? (ctl/layout? parent) + auto? (or (ctl/auto-height? transformed-parent) (ctl/auto-width? transformed-parent)) + parent? (or (cph/group-like-shape? parent) (cph/frame-shape? parent)) ;; If the current child is inside the layout we ignore the constraints - is-inside-layout? (ctl/inside-layout? objects parent)] + inside-layout? (ctl/inside-layout? objects parent)] [(cond-> modif-tree - (and (not is-layout?) has-modifiers? is-parent? (not root?)) - (set-children-modifiers objects parent transformed-parent (or ignore-constraints is-inside-layout?)) + (and (not layout?) has-modifiers? parent? (not root?)) + (set-children-modifiers objects parent transformed-parent (or ignore-constraints inside-layout?)) - is-layout? + layout? (-> (process-layout-children objects parent transformed-parent) - (set-layout-modifiers objects transformed-parent)) + (set-layout-modifiers objects transformed-parent))) - is-auto? - (set-auto-modifiers objects transformed-parent)) + ;; Auto-width/height can change the positions in the parent so we need to recalculate + (cond-> autolayouts auto? (conj (:id parent)))])) - (cond-> recalculate - ;; Auto-width/height can change the positions in the parent so we need to recalculate - is-auto? - (conj (:id parent)))])) +(defn- apply-structure-modifiers + [objects modif-tree] + (letfn [(apply-shape [objects [id {:keys [modifiers]}]] + (if (ctm/has-structure? modifiers) + (let [shape (get objects id)] + (update objects id ctm/apply-structure-modifiers modifiers)) + objects))] + (reduce apply-shape objects modif-tree))) -(defn- calculate-reflow-layout - [objects modif-tree parent] - (let [is-layout? (ctl/layout? parent) - is-auto? (or (ctl/auto-height? parent) (ctl/auto-width? parent)) - modifiers (dm/get-in modif-tree [(:id parent) :modifiers]) - transformed-parent (gtr/transform-shape parent modifiers)] - (cond-> modif-tree - is-layout? - (set-layout-modifiers objects transformed-parent) +(defn- apply-partial-objects-modifiers + [objects tree-seq modif-tree] - is-auto? - (set-auto-modifiers objects transformed-parent)))) + (letfn [(apply-shape [objects {:keys [id] :as shape}] + (if (cph/group-shape? shape) + (let [children (cph/get-children objects id)] + (assoc objects id + (cond + (cph/mask-shape? shape) + (gtr/update-mask-selrect shape children) + + :else + (gtr/update-group-selrect shape children)))) + + (let [modifiers (get-in modif-tree [id :modifiers]) + object (cond-> shape + (some? modifiers) + (gtr/transform-shape modifiers))] + (assoc objects id object))))] + + (reduce apply-shape objects (reverse tree-seq)))) + +(defn merge-modif-tree + [modif-tree other-tree] + (reduce (fn [modif-tree [id {:keys [modifiers]}]] + (update-in modif-tree [id :modifiers] ctm/add-modifiers modifiers)) + modif-tree + other-tree)) + +(defn sizing-auto-modifiers + "Recalculates the layouts to adjust the sizing: auto new sizes" + [modif-tree sizing-auto-layouts objects ignore-constraints] + (loop [modif-tree modif-tree + sizing-auto-layouts (reverse sizing-auto-layouts)] + (if-let [current (first sizing-auto-layouts)] + (let [parent-base (get objects current) + tree-seq (resolve-tree-sequence #{current} objects) + + ;; Apply the current stack of transformations so we can calculate the auto-layouts + objects (apply-partial-objects-modifiers objects tree-seq modif-tree) + + resize-modif-tree + {current {:modifiers (calc-auto-modifiers objects parent-base)}} + + tree-seq (resolve-tree-sequence #{current} objects) + + [resize-modif-tree _] + (reduce (partial propagate-modifiers objects ignore-constraints) [resize-modif-tree #{}] tree-seq) + + modif-tree (merge-modif-tree modif-tree resize-modif-tree)] + (recur modif-tree (rest sizing-auto-layouts))) + modif-tree))) (defn set-objects-modifiers [modif-tree objects ignore-constraints snap-pixel?] - (let [shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) + (let [objects (apply-structure-modifiers objects modif-tree) + shapes-tree (resolve-tree-sequence (-> modif-tree keys set) objects) - [modif-tree recalculate] + [modif-tree sizing-auto-layouts] (reduce (partial propagate-modifiers objects ignore-constraints) [modif-tree #{}] shapes-tree) - shapes-tree (resolve-tree-sequence recalculate objects) - - ;; We need to go again and recalculate the layout positions+hug - ;; TODO LAYOUT: How to remove this recalculation? - modif-tree - (->> shapes-tree - reverse - (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects) modif-tree)) - - modif-tree - (->> shapes-tree - (filter ctl/layout?) - (reduce (partial calculate-reflow-layout objects) modif-tree)) + ;; Calculate hug layouts positions + modif-tree (sizing-auto-modifiers modif-tree sizing-auto-layouts objects ignore-constraints) modif-tree (cond-> modif-tree diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 04ac8fc27..f2c63f5df 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -369,6 +369,9 @@ ;; Points for every shape inside the group points (->> children (mapcat :points)) + ;; Fixed problem with empty groups. Should not happen (but it does) + points (if (empty? points) (:points group) points) + ;; Invert to get the points minus the transforms applied to the group base-points (gco/transform-points points shape-center (:transform-inverse group (gmt/matrix))) @@ -478,43 +481,43 @@ (declare apply-group-modifiers) (defn apply-children-modifiers - [objects modif-tree parent-modifiers children] + [objects modif-tree parent-modifiers children propagate?] (->> children (map (fn [child] - (let [modifiers (->> (get-in modif-tree [(:id child) :modifiers]) - (ctm/add-modifiers parent-modifiers)) + (let [modifiers (cond-> (get-in modif-tree [(:id child) :modifiers]) + propagate? (ctm/add-modifiers parent-modifiers)) child (transform-shape child modifiers) - parent? (cph/group-like-shape? child)] + parent? (cph/group-like-shape? child) + + modif-tree + (cond-> modif-tree + propagate? + (assoc-in [(:id child) :modifiers] modifiers))] + (cond-> child parent? - (apply-group-modifiers objects (assoc-in modif-tree [(:id child) :modifiers] modifiers)))))))) + (apply-group-modifiers objects modif-tree propagate?))))))) (defn apply-group-modifiers "Apply the modifiers to the group children to calculate its selection rect" - [group objects modif-tree] + ([group objects modif-tree] + (apply-group-modifiers group objects modif-tree true)) - (let [modifiers (get-in modif-tree [(:id group) :modifiers]) - children (->> (:shapes group) - (map (d/getf objects)) - (apply-children-modifiers objects modif-tree modifiers))] - (cond - (cph/mask-shape? group) - (update-mask-selrect group children) + ([group objects modif-tree propagate?] + (let [modifiers (get-in modif-tree [(:id group) :modifiers]) + children + (as-> (:shapes group) $ + (map (d/getf objects) $) + (apply-children-modifiers objects modif-tree modifiers $ propagate?))] + (cond + (cph/mask-shape? group) + (update-mask-selrect group children) - (cph/group-shape? group) - (update-group-selrect group children) + (cph/group-shape? group) + (update-group-selrect group children) - :else - group))) - -(defn get-children-bounds - [parent objects modif-tree] - (let [modifiers (get-in modif-tree [(:id parent) :modifiers]) - children - (->> (:shapes parent) - (map (d/getf objects)) - (apply-children-modifiers objects modif-tree modifiers))] - (->> children (mapcat :points) gpr/points->rect))) + :else + group)))) (defn parent-coords-rect [child parent] diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 61af67564..d95d0d31f 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -384,7 +384,11 @@ (defn select-structure [modifiers] - (select-keys modifiers [:structure-parent])) + (select-keys modifiers [:structure-parent :structure-child])) + +(defn select-geometry + [modifiers] + (select-keys modifiers [:geometry-parent :geometry-child])) (defn added-children-frames "Returns the frames that have an 'add-children' operation"