From 8d9ed4f8af8bba6b04d18266409158326002e184 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 30 Sep 2022 15:36:30 +0200 Subject: [PATCH] :sparkles: Fill elements in auto-layout --- common/src/app/common/geom/shapes/layout.cljc | 150 +++++++++++++----- .../app/common/geom/shapes/transforms.cljc | 1 + common/src/app/common/types/modifiers.cljc | 5 + .../shapes/frame/dynamic_modifiers.cljs | 50 +++--- .../shapes/text/viewport_texts_html.cljs | 27 ++-- .../sidebar/options/menus/constraints.cljs | 2 +- .../sidebar/options/menus/measures.cljs | 2 +- .../src/app/main/ui/workspace/viewport.cljs | 2 +- .../ui/workspace/viewport/frame_grid.cljs | 3 +- 9 files changed, 162 insertions(+), 80 deletions(-) diff --git a/common/src/app/common/geom/shapes/layout.cljc b/common/src/app/common/geom/shapes/layout.cljc index e6f7cc70e..658b09fc7 100644 --- a/common/src/app/common/geom/shapes/layout.cljc +++ b/common/src/app/common/geom/shapes/layout.cljc @@ -6,6 +6,7 @@ (ns app.common.geom.shapes.layout (:require + [app.common.data :as d] [app.common.geom.point :as gpt] [app.common.geom.shapes.rect :as gre])) @@ -70,18 +71,25 @@ (let [wrap? (= layout-wrap-type :wrap) reduce-fn - (fn [[{:keys [line-width line-height num-children child-fill? num-child-fill] :as line-data} result] child] + (fn [[{:keys [line-width line-height num-children line-fill? child-fill? num-child-fill] :as line-data} result] child] (let [child-bounds (-> child :points gre/points->rect) cur-child-fill? (or (and (col? shape) (= :fill (:layout-h-behavior child))) (and (row? shape) (= :fill (:layout-v-behavior child)))) - next-width (if cur-child-fill? + cur-line-fill? + (or (and (row? shape) (= :fill (:layout-h-behavior child))) + (and (col? shape) (= :fill (:layout-v-behavior child)))) + + ;; TODO LAYOUT: ADD MINWIDTH/HEIGHT + next-width (if (or (and (col? shape) cur-child-fill?) + (and (row? shape) cur-line-fill?)) 0 (-> child-bounds :width)) - next-height (if cur-child-fill? + next-height (if (or (and (row? shape) cur-child-fill?) + (and (col? shape) cur-line-fill?)) 0 (-> child-bounds :height))] @@ -90,19 +98,21 @@ (and (col? shape) (<= (+ line-width next-width (* layout-gap num-children)) width)) (and (row? shape) (<= (+ line-height next-height (* layout-gap num-children)) height)))) - ;; Si autofill aƱadimos el minwidth que por defecto es 0 + ;; When :fill we add min width (0 by default) [{:line-width (if (col? shape) (+ line-width next-width) (max line-width next-width)) :line-height (if (row? shape) (+ line-height next-height) (max line-height next-height)) :num-children (inc num-children) :child-fill? (or cur-child-fill? child-fill?) + :line-fill? (or cur-line-fill? line-fill?) :num-child-fill (cond-> num-child-fill cur-child-fill? inc)} result] [{:line-width next-width :line-height next-height :num-children 1 - :child-fill? child-fill? - :num-child-fill (if child-fill? 1 0)} + :child-fill? cur-child-fill? + :line-fill? cur-line-fill? + :num-child-fill (if cur-child-fill? 1 0)} (cond-> result (some? line-data) (conj line-data))]))) [line-data layout-lines] (reduce reduce-fn [nil []] children)] @@ -142,10 +152,16 @@ (let [children-gap (* layout-gap (dec num-children)) + line-width (if (and (col? shape) child-fill?) (- width (* layout-gap num-children)) line-width) + line-height (if (and (row? shape) child-fill?) (- height (* layout-gap num-children)) line-height) + start-x (cond - (or (and (col? shape) child-fill?) - (and (col? shape) (= :space-between layout-type)) + ;;(and (col? shape) child-fill?) + ;;;; TODO LAYOUT: Start has to take into account max-width + ;;x + + (or (and (col? shape) (= :space-between layout-type)) (and (col? shape) (= :space-around layout-type))) x @@ -169,8 +185,11 @@ start-y (cond - (or (and (row? shape) child-fill?) - (and (row? shape) (= :space-between layout-type)) + ;;(and (row? shape) child-fill?) + ;;;; TODO LAYOUT: Start has to take into account max-width + ;;y + + (or (and (row? shape) (= :space-between layout-type)) (and (row? shape) (= :space-around layout-type))) y @@ -191,6 +210,7 @@ :else y)] + [start-x start-y])) (get-next-line @@ -213,12 +233,27 @@ next-x next-y]))] - (let [[total-width total-height] - (->> layout-lines (reduce add-lines [0 0])) + (let [[total-width total-height] (->> layout-lines (reduce add-lines [0 0])) total-width (+ total-width (* layout-gap (dec (count layout-lines)))) total-height (+ total-height (* layout-gap (dec (count layout-lines)))) + vertical-fill-space (- height total-height) + horizontal-fill-space (- width total-width) + num-line-fill (count (->> layout-lines (filter :line-fill?))) + + layout-lines + (->> layout-lines + (mapv #(cond-> % + (and (col? shape) (:line-fill? %)) + (update :line-height + (/ vertical-fill-space num-line-fill)) + + (and (row? shape) (:line-fill? %)) + (update :line-width + (/ horizontal-fill-space num-line-fill))))) + + total-height (if (and (col? shape) (> num-line-fill 0)) height total-height) + total-width (if (and (row? shape) (> num-line-fill 0)) width total-width) + [base-x base-y] (get-base-line total-width total-height) @@ -305,6 +340,7 @@ :else start-y) + pos-x (cond-> pos-x (some? margin-x) (+ margin-x)) pos-y (cond-> pos-y (some? margin-y) (+ margin-y)) @@ -323,47 +359,83 @@ next-x (cond-> next-x (some? margin-x) (+ margin-x)) next-y (cond-> next-y (some? margin-y) (+ margin-y)) + layout-data (assoc layout-data :start-x next-x :start-y next-y)] [corner-p layout-data])) +(defn calc-fill-width-data + [child-bounds + {:keys [layout-gap] :as parent} + {:keys [layout-h-behavior] :as child} + {:keys [num-children line-width layout-bounds line-fill? child-fill?] :as layout-data}] + + (cond + (and (col? parent) (= :fill layout-h-behavior) child-fill?) + (let [fill-space (- (:width layout-bounds) line-width (* layout-gap num-children)) + fill-width (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-width (:width child-bounds))] + {:bounds {:width fill-width} + :modifiers [{:type :resize + :origin (gpt/point child-bounds) + :vector (gpt/point fill-scale 1)}]}) + + (and (row? parent) (= :fill layout-h-behavior) line-fill?) + (let [fill-scale (/ line-width (:width child-bounds))] + {:bounds {:width line-width} + :modifiers [{:type :resize + :origin (gpt/point child-bounds) + :vector (gpt/point fill-scale 1)}]}) + )) + +(defn calc-fill-height-data + [child-bounds + {:keys [layout-gap] :as parent} + {:keys [layout-v-behavior] :as child} + {:keys [num-children line-height layout-bounds line-fill? child-fill?] :as layout-data}] + + (cond + (and (row? parent) (= :fill layout-v-behavior) child-fill?) + (let [fill-space (- (:height layout-bounds) line-height (* layout-gap num-children)) + fill-height (/ fill-space (:num-child-fill layout-data)) + fill-scale (/ fill-height (:height child-bounds))] + {:bounds {:height fill-height} + :modifiers [{:type :resize + :origin (gpt/point child-bounds) + :vector (gpt/point 1 fill-scale)}]}) + + (and (col? parent) (= :fill layout-v-behavior) line-fill?) + (let [fill-scale (/ line-height (:height child-bounds))] + {:bounds {:height line-height} + :modifiers [{:type :resize + :origin (gpt/point child-bounds) + :vector (gpt/point 1 fill-scale)}]}) + )) + (defn calc-layout-modifiers "Calculates the modifiers for the layout" [parent transform child layout-data] - (let [child-bounds (-> child :points gre/points->selrect) - fill-space (- (-> layout-data :layout-bounds :width) (:line-width layout-data)) + fill-width (calc-fill-width-data child-bounds parent child layout-data) + fill-height (calc-fill-height-data child-bounds parent child layout-data) - fill-width (- (/ fill-space (:num-child-fill layout-data)) - (* 2 (:layout-gap layout-data))) - - fill-scale (/ fill-width (:width child-bounds)) - - child-bounds - (cond-> child-bounds - (and (col? parent) (= :fill (:layout-h-behavior child))) - (assoc :width fill-width)) + child-bounds (cond-> child-bounds + fill-width (merge (:bounds fill-width)) + fill-height (merge (:bounds fill-height))) [corner-p layout-data] (next-p parent child-bounds layout-data) - delta-p (-> corner-p - (gpt/subtract (gpt/point child-bounds)) - (cond-> (some? transform) (gpt/transform transform))) - - modifiers [] + delta-p + (-> corner-p + (gpt/subtract (gpt/point child-bounds)) + (cond-> (some? transform) (gpt/transform transform))) modifiers - (cond-> modifiers - (and (col? parent) (= :fill (:layout-h-behavior child))) - (conj {:type :resize - :from :layout - :origin (gpt/point child-bounds) - :vector (gpt/point fill-scale 1)})) - - modifiers - (conj modifiers {:type :move - :from :layout - :vector delta-p})] + (-> [] + (cond-> fill-width (d/concat-vec (:modifiers fill-width))) + (cond-> fill-height (d/concat-vec (:modifiers fill-height))) + (conj {:type :move :vector delta-p}))] [modifiers layout-data])) + diff --git a/common/src/app/common/geom/shapes/transforms.cljc b/common/src/app/common/geom/shapes/transforms.cljc index 8b1dfaa36..5f1d160b6 100644 --- a/common/src/app/common/geom/shapes/transforms.cljc +++ b/common/src/app/common/geom/shapes/transforms.cljc @@ -91,6 +91,7 @@ (defn- calculate-height "Calculates the height of a parallelogram given by the points" [[p1 _ _ p4]] + (-> (gpt/to-vec p4 p1) (gpt/length))) diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index 963bcd74f..7c8658cfb 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -254,3 +254,8 @@ (gmt/multiply (gmt/rotate-matrix rt-modif)) (gmt/translate (gpt/negate center)))))) )) + +(defn only-move? + [modifier] + (and (= 1 (-> modifier :v2 count)) + (= :move (-> modifier :v2 first :type)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 565cca9d5..0ea026601 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -111,8 +111,7 @@ (dom/query-all shape-defs ".svg-mask-wrapper"))) text? - [shape-node - (dom/query shape-node ".text-container")] + [shape-node] :else [shape-node])))) @@ -178,12 +177,10 @@ (defn update-transform! [base-node shapes transforms modifiers] - (doseq [{:keys [id type] :as shape} shapes] + (doseq [{:keys [id _type] :as shape} shapes] (when-let [nodes (get-nodes base-node shape)] (let [transform (get transforms id) - modifiers (get-in modifiers [id :modifiers]) - text? (= type :text) - transform-text? (and text? (and (nil? (:resize-vector modifiers)) (nil? (:resize-vector-2 modifiers))))] + modifiers (get-in modifiers [id :modifiers])] ;; TODO LAYOUT: Adapt to new modifiers (doseq [node nodes] @@ -197,19 +194,10 @@ (dom/class? node "frame-children") (set-transform-att! node "transform" (gmt/inverse transform)) - (dom/class? node "text-container") - (let [modifiers (dissoc modifiers :displacement :rotation)] - (when (not (ctm/empty-modifiers? modifiers)) - (let [mtx (-> shape - (assoc :modifiers modifiers) - (gsh/transform-shape) - (gsh/transform-matrix {:no-flip true}))] - (override-transform-att! node "transform" mtx)))) - (dom/class? node "frame-title") - (let [shape (-> shape (assoc :modifiers modifiers) gsh/transform-shape) - zoom (get-in @st/state [:workspace-local :zoom] 1) - mtx (vwu/title-transform shape zoom)] + (let [shape (gsh/transform-shape shape modifiers) + zoom (get-in @st/state [:workspace-local :zoom] 1) + mtx (vwu/title-transform shape zoom)] (override-transform-att! node "transform" mtx)) (or (= (dom/get-tag-name node) "mask") @@ -223,7 +211,7 @@ (= (dom/get-tag-name node) "pattern") (set-transform-att! node "patternTransform" transform) - (and (some? transform) (some? node) (or (not text?) transform-text?)) + (and (some? transform) (some? node)) (set-transform-att! node "transform" transform))))))) (defn remove-transform! @@ -251,6 +239,20 @@ (dom/remove-attribute! node "data-old-transform") (dom/remove-attribute! node "transform"))))))))) +(defn adapt-text-modifiers + [modifiers shape] + (let [shape' (gsh/transform-shape shape modifiers) + scalev + (gpt/point (/ (:width shape) (:width shape')) + (/ (:height shape) (:height shape')))] + ;; Reverse the change in size so we can recalculate the layout + (-> modifiers + (update :v2 conj {:type :resize + :vector scalev + :transform (:transform shape') + :transform-inverse (:transform-inverse shape') + :origin (-> shape' :points first)})))) + (defn use-dynamic-modifiers [objects node modifiers] @@ -262,14 +264,8 @@ (d/mapm (fn [id {modifiers :modifiers}] (let [shape (get objects id) center (gsh/center-shape shape) - - ;; TODO LAYOUT: Adapt to new modifiers - modifiers (cond-> modifiers - ;; For texts we only use the displacement because - ;; resize needs to recalculate the text layout - (= :text (:type shape)) - (select-keys [:displacement :rotation])) - ] + text? (= :text (:type shape)) + modifiers (cond-> modifiers text? (adapt-text-modifiers shape))] (ctm/modifiers->transform center modifiers))) modifiers)))) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index e104b64fa..74e8057e0 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.geom.shapes.text :as gsht] [app.common.math :as mth] @@ -34,21 +35,29 @@ (with-meta (meta (:position-data shape)))) (dissoc :position-data :transform :transform-inverse))) -;; TODO LAYOUT: Adapt to new modifiers -(defn strip-modifier +#_(defn strip-modifier [modifier] (if (or (some? (dm/get-in modifier [:modifiers :resize-vector])) (some? (dm/get-in modifier [:modifiers :resize-vector-2]))) modifier (d/update-when modifier :modifiers dissoc :displacement :rotation))) +(defn fix-position [shape modifier] + (let [shape' (-> shape + (assoc :grow-type :fixed) + (gsh/transform-shape modifier)) + + deltav (gpt/to-vec (gpt/point (:selrect shape')) + (gpt/point (:selrect shape)))] + (gsh/transform-shape shape' (ctm/move deltav)))) + (defn process-shape [modifiers {:keys [id] :as shape}] - (let [modifier (-> (get modifiers id) strip-modifier) - shape (cond-> shape - (not (ctm/empty-modifiers? (:modifiers modifier))) - (-> (assoc :grow-type :fixed) - (gsh/transform-shape modifier)))] + (let [modifier (dm/get-in modifiers [id :modifiers])] (-> shape + (cond-> (and (some? modifier) + (not (ctm/only-move? modifier))) + (fix-position modifier)) + (cond-> (nil? (:position-data shape)) (assoc :migrate true)) strip-position-data))) @@ -138,8 +147,8 @@ (fn [id] (let [new-shape (get text-shapes id) old-shape (get prev-text-shapes id) - old-modifiers (-> (get prev-modifiers id) strip-modifier) - new-modifiers (-> (get modifiers id) strip-modifier) + old-modifiers (get prev-modifiers id) + new-modifiers (get modifiers id) remote? (some? (-> new-shape meta :session-id)) ] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index d7ea7c715..4d22ffa54 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -30,7 +30,7 @@ frames (map #(deref (refs/object-by-id (:frame-id %))) old-shapes) shapes (as-> old-shapes $ - (map gsh/transform-shape $) + #_(map gsh/transform-shape $) (map gsh/translate-to-frame $ frames)) values (let [{:keys [x y]} (-> shapes first :points gsh/points->selrect)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 307b19164..8a9e73f3c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -83,7 +83,7 @@ ;; the shape with the mouse, generate a copy of the shapes applying ;; the transient transformations. shapes (as-> old-shapes $ - (map gsh/transform-shape $) + #_(map gsh/transform-shape $) (map gsh/translate-to-frame $ frames)) ;; For rotated or stretched shapes, the origin point we show in the menu diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index f5044bd0d..5a4be44ca 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -202,7 +202,7 @@ {:key (dm/str "texts-" page-id) :page-id page-id :objects objects - ;;:modifiers modifiers + :modifiers modifiers :edition edition}]]]] (when show-comments? diff --git a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs index a26d7c6ab..c7b403286 100644 --- a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.viewport.frame-grid (:require [app.common.data :as d] - [app.common.geom.shapes :as gsh] [app.common.math :as mth] [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] @@ -138,4 +137,4 @@ (or (empty? focus) (contains? focus (:id frame)))) [:& grid-display-frame {:key (str "grid-" (:id frame)) :zoom zoom - :frame (gsh/transform-shape frame)}]))])) + :frame frame}]))]))