From d420f30835023536d6264dd16104237e4aff9dd2 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 2 Oct 2023 16:01:57 +0200 Subject: [PATCH 1/8] :sparkles: Grid area attributes for html generation --- common/src/app/common/types/shape/layout.cljc | 61 +++++++++++++++++-- .../app/main/data/workspace/shape_layout.cljs | 43 ++++++++----- .../app/main/data/workspace/transforms.cljs | 4 +- frontend/src/app/util/code_gen/style_css.cljs | 2 + .../app/util/code_gen/style_css_values.cljs | 41 +++++++++++-- 5 files changed, 126 insertions(+), 25 deletions(-) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 9abd71970a..cccafdb200 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -735,6 +735,19 @@ (maybe-remove?) (map (fn [[id cell]] (assoc cell :id id))))))) +(defn cells-seq + [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] + + (let [comp-fn (if (= layout-grid-dir :row) + (juxt :row :column) + (juxt :column :row)) + maybe-sort? + (if sort? (partial sort-by (comp comp-fn second)) identity)] + + (->> layout-grid-cells + (maybe-sort?) + (map second)))) + (defn get-free-cells ([parent] (get-free-cells parent nil)) @@ -782,7 +795,7 @@ (reduce find-overlaps #{} cells))) ;; FIXME: This is only for development -#_(defn fix-overlaps +(defn fix-overlaps [parent overlaps] (reduce (fn [parent ids] (let [id (if (empty? (get-in parent [:layout-grid-cells (first ids)])) @@ -792,6 +805,32 @@ parent overlaps)) +(defn position-auto-shapes + [parent] + ;; Iterate through the cells. While auto and contains shape no changes. + ;; If auto without shape start moving auto + ;; Move shapes in auto-cells to the first free auto. + (let [auto-cells (->> (cells-seq parent :sort? true) + (filter #(and (= (:position %) :auto) + (= (:row-span %) 1) + (= (:column-span %) 1)))) + + shapes (->> auto-cells (mapcat :shapes)) + + parent + (loop [parent parent + cells (seq auto-cells) + shapes (seq shapes)] + (if (empty? cells) + parent + (let [shape (first shapes) + cell (first cells) + parent (assoc-in parent [:layout-grid-cells (:id cell) :shapes] (if (some? shape) [shape] []))] + (recur parent + (rest cells) + (rest shapes)))))] + parent)) + ;; Assign cells takes the children and move them into the allotted cells. If there are not enough cells it creates ;; not-tracked rows/columns and put the shapes there ;; Non-tracked tracks need to be deleted when they are empty and there are no more shapes unallocated @@ -803,13 +842,21 @@ ;; - (maybe) create group/frames. This case will assigna a cell that had one of its children (defn assign-cells [parent] - (let [parent (-> parent check-deassigned-cells) + (let [;; TODO: Remove this, shouldn't be happening + ;;overlaps (overlapping-cells parent) + ;;_ (when (not (empty? overlaps)) + ;; (.warn js/console "OVERLAPS" overlaps)) + parent (cond-> (check-deassigned-cells parent) + #_(d/not-empty? overlaps) + #_(fix-overlaps overlaps)) shape-has-cell? (into #{} (mapcat (comp :shapes second)) (:layout-grid-cells parent)) no-cell-shapes - (->> (:shapes parent) (remove shape-has-cell?))] + (->> (:shapes parent) (remove shape-has-cell?)) + + parent (position-auto-shapes parent)] (if (empty? no-cell-shapes) ;; All shapes are within a cell. No need to assign @@ -840,9 +887,10 @@ (reduce (fn [parent _] (add-track parent default-track-value)) parent)) cells - (loop [cells (:layout-grid-cells parent) + (loop [cells (:layout-grid-cells parent) free-cells (get-free-cells parent {:sort? true}) - pending no-cell-shapes] + pending no-cell-shapes] + (if (or (empty? free-cells) (empty? pending)) cells (let [next-free (first free-cells) @@ -924,7 +972,8 @@ (reduce (fn [[parent cells] [shape-id idx]] (let [[parent cells] (free-cell-push parent cells idx)] [(update-in parent [:layout-grid-cells (get-in cells [idx :id])] - assoc :position :manual :shapes [shape-id]) + assoc :position :manual + :shapes [shape-id]) cells])) [parent cells]) (first))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index bc645e92d2..45dd0d30c9 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -598,8 +598,34 @@ (dwc/update-shapes [layout-id] (fn [shape] - (cond - (= mode :area) + (case mode + :auto + ;; change the manual cells and move to auto + (->> ids + (reduce + (fn [shape cell-id] + (let [cell (get-in shape [:layout-grid-cells cell-id])] + (cond-> shape + (or (contains? #{:area :manual} (:position cell)) + (> (:row-span cell) 1) + (> (:column-span cell) 1)) + (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) + (ctl/resize-cell-area (:row cell) (:column cell) (:row cell) (:column cell) 1 1) + (ctl/assign-cells))))) + shape)) + + :manual + (->> ids + (reduce + (fn [shape cell-id] + (let [cell (get-in shape [:layout-grid-cells cell-id])] + (cond-> shape + (contains? #{:area :auto} (:position cell)) + (-> (d/assoc-in-when [:layout-grid-cells cell-id :position] :manual) + (ctl/assign-cells))))) + shape)) + + :area ;; Create area with the selected cells (let [{:keys [first-row first-column last-row last-column]} (ctl/cells-coordinates (->> ids (map #(get-in shape [:layout-grid-cells %])))) @@ -618,18 +644,7 @@ (ctl/assign-cells))] (-> shape - (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area))) - - (= mode :auto) - ;; change the manual cells and move to auto - (->> ids - (reduce - (fn [shape cell-id] - (cond-> shape - (contains? #{:area :manual} (get-in shape [:layout-grid-cells cell-id :position])) - (-> (d/update-in-when [:layout-grid-cells cell-id] assoc :shapes [] :position :auto) - (ctl/assign-cells)))) - shape))))) + (d/update-in-when [:layout-grid-cells (:id target-cell)] assoc :position :area)))))) (dwge/clean-selection layout-id) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 593dcb6949..ce1cd5a1dd 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -611,7 +611,9 @@ (ctl/swap-shapes id (:id next-cell))))) parent))] (-> changes - (pcb/update-shapes [(:id parent)] (fn [shape] (assoc shape :layout-grid-cells layout-grid-cells))) + (pcb/update-shapes [(:id parent)] (fn [shape] (-> shape + (assoc :layout-grid-cells layout-grid-cells) + (ctl/assign-cells)))) (pcb/reorder-grid-children [(:id parent)])))) changes diff --git a/frontend/src/app/util/code_gen/style_css.cljs b/frontend/src/app/util/code_gen/style_css.cljs index a17e454df5..5ab4655c12 100644 --- a/frontend/src/app/util/code_gen/style_css.cljs +++ b/frontend/src/app/util/code_gen/style_css.cljs @@ -100,6 +100,7 @@ body { ;; Grid related properties :grid-template-rows :grid-template-columns + :grid-template-areas ;; Flex/grid self properties :flex-shrink @@ -114,6 +115,7 @@ body { ;; Grid cell properties :grid-column :grid-row + :grid-area ]) (def text-node-css-properties diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index 5c11a80056..e2e184de41 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -14,7 +14,8 @@ [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] [app.main.ui.formats :as fmt] - [app.util.code-gen.common :as cgc])) + [app.util.code-gen.common :as cgc] + [cuerdas.core :as str])) (defn fill->color [{:keys [fill-color fill-opacity fill-color-gradient]}] @@ -279,15 +280,38 @@ [_ shape _] (:layout-grid-columns shape)) +(defmethod get-value :grid-template-areas + [_ shape _] + (when (ctl/grid-layout? shape) + (let [result + (->> (d/enumerate (:layout-grid-rows shape)) + (map + (fn [[row _]] + (dm/str + "\"" + (->> (d/enumerate (:layout-grid-columns shape)) + (map (fn [[column _]] + (let [cell (ctl/get-cell-by-position shape (inc row) (inc column))] + (str/replace (:area-name cell ".") " " "-")))) + (str/join " ")) + "\""))) + (str/join "\n"))] + result))) + (defn get-grid-coord [shape objects prop span-prop] (when (and (ctl/grid-layout-immediate-child? objects shape) (not (ctl/layout-absolute? shape))) (let [parent (get objects (:parent-id shape)) cell (ctl/get-cell-by-shape-id parent (:id shape))] - (if (> (get cell span-prop) 1) - (dm/str (get cell prop) " / " (+ (get cell prop) (get cell span-prop))) - (get cell prop))))) + (when (and + (not (and (= (:position cell) :area) (d/not-empty? (:area-name cell)))) + (or (= (:position cell) :manual) + (> (:row-span cell) 1) + (> (:column-span cell) 1))) + (if (> (get cell span-prop) 1) + (dm/str (get cell prop) " / " (+ (get cell prop) (get cell span-prop))) + (get cell prop)))))) (defmethod get-value :grid-column [_ shape objects] @@ -297,6 +321,15 @@ [_ shape objects] (get-grid-coord shape objects :row :row-span)) +(defmethod get-value :grid-area + [_ shape objects] + (when (and (ctl/grid-layout-immediate-child? objects shape) + (not (ctl/layout-absolute? shape))) + (let [parent (get objects (:parent-id shape)) + cell (ctl/get-cell-by-shape-id parent (:id shape))] + (when (and (= (:position cell) :area) (d/not-empty? (:area-name cell))) + (str/replace (:area-name cell) " " "-"))))) + (defmethod get-value :flex-shrink [_ shape objects] (when (and (ctl/flex-layout-immediate-child? objects shape) From a45bc0177b7edc7640596f4b551e3939025bd65f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 2 Oct 2023 17:22:10 +0200 Subject: [PATCH 2/8] :bug: Fix problem with grid --- .../geom/shapes/grid_layout/layout_data.cljc | 31 +++++++++---- common/src/app/common/types/shape/layout.cljc | 43 ++++++------------- .../app/util/code_gen/style_css_values.cljs | 8 ++-- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index 72c1ea18f9..5e3595ee20 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -228,16 +228,17 @@ (defn allocate-auto-tracks [allocations indexed-tracks to-allocate] (if (empty? indexed-tracks) - allocations + [allocations to-allocate] (let [[idx track] (first indexed-tracks) old-allocated (get allocations idx 0.01) auto-track? (= :auto (:type track)) - allocated (if auto-track? - (max old-allocated - (/ to-allocate (count indexed-tracks)) - (:size track)) - (:size track))] + allocated + (if auto-track? + (max old-allocated + (/ to-allocate (count indexed-tracks)) + (:size track)) + (:size track))] (recur (cond-> allocations auto-track? (assoc idx allocated)) @@ -304,8 +305,22 @@ [to-allocate (conj result idx-track)] ;; If fixed, we remove from allocate and don't add the track [(- to-allocate (:size track)) result])) - [to-allocate []]))] - (allocate-auto-tracks allocated indexed-tracks (max to-allocate 0)))) + [to-allocate []])) + + + non-assigned-indexed-tracks + (->> indexed-tracks + (remove (fn [[idx track]] (contains? allocated idx)))) + + ;; First we try to assign into the non-assigned tracks + [allocated to-allocate] + (allocate-auto-tracks allocated non-assigned-indexed-tracks (max to-allocate 0)) + + ;; In the second pass we use every track for the rest of the space + [allocated _] + (allocate-auto-tracks allocated indexed-tracks (max to-allocate 0))] + + allocated)) {})) ;; Apply the allocations to the tracks diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index cccafdb200..7c0b6a97ac 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -715,26 +715,6 @@ [parent from-index to-index] (reorder-grid-track :layout-grid-rows parent from-index to-index)) -(defn get-cells - ([parent] - (get-cells parent nil)) - - ([{:keys [layout-grid-cells layout-grid-dir]} {:keys [sort? remove-empty?] :or {sort? false remove-empty? false}}] - (let [comp-fn (if (= layout-grid-dir :row) - (juxt :row :column) - (juxt :column :row)) - - maybe-sort? - (if sort? (partial sort-by (comp comp-fn second)) identity) - - maybe-remove? - (if remove-empty? (partial remove #(empty? (:shapes (second %)))) identity)] - - (->> layout-grid-cells - (maybe-sort?) - (maybe-remove?) - (map (fn [[id cell]] (assoc cell :id id))))))) - (defn cells-seq [{:keys [layout-grid-cells layout-grid-dir]} & {:keys [sort?] :or {sort? false}}] @@ -752,18 +732,21 @@ ([parent] (get-free-cells parent nil)) - ([{:keys [layout-grid-cells layout-grid-dir]} {:keys [sort?] :or {sort? false}}] - (let [comp-fn (if (= layout-grid-dir :row) - (juxt :row :column) - (juxt :column :row)) + ([parent {:keys [sort?] :or {sort? false}}] + (->> (cells-seq parent :sort? sort?) + (filter (comp empty? :shapes)) + (map :id)))) - maybe-sort? - (if sort? (partial sort-by (comp comp-fn second)) identity)] +(defn get-cells + ([parent] + (get-cells parent nil)) - (->> layout-grid-cells - (filter (comp empty? :shapes second)) - (maybe-sort?) - (map first))))) + ([parent {:keys [sort? remove-empty?] :or {sort? false remove-empty? false}}] + (let [maybe-remove? + (if remove-empty? (partial remove (comp empty? :shapes)) identity)] + + (->> (cells-seq parent :sort? sort?) + (maybe-remove?))))) (defn check-deassigned-cells "Clean the cells whith shapes that are no longer in the layout" diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index e2e184de41..a5f1e88345 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -367,13 +367,13 @@ (defmethod get-value :max-height [_ shape objects] (cond - (ctl/flex-layout-immediate-child? objects shape) + (ctl/any-layout-immediate-child? objects shape) (:layout-item-max-h shape))) (defmethod get-value :min-height [_ shape objects] (cond - (and (ctl/flex-layout-immediate-child? objects shape) (some? (:layout-item-min-h shape))) + (and (ctl/any-layout-immediate-child? objects shape) (some? (:layout-item-min-h shape))) (:layout-item-min-h shape) (and (ctl/auto-height? shape) (cph/frame-shape? shape) (not (:show-content shape))) @@ -382,13 +382,13 @@ (defmethod get-value :max-width [_ shape objects] (cond - (ctl/flex-layout-immediate-child? objects shape) + (ctl/any-layout-immediate-child? objects shape) (:layout-item-max-w shape))) (defmethod get-value :min-width [_ shape objects] (cond - (and (ctl/flex-layout-immediate-child? objects shape) (some? (:layout-item-min-w shape))) + (and (ctl/any-layout-immediate-child? objects shape) (some? (:layout-item-min-w shape))) (:layout-item-min-w shape) (and (ctl/auto-width? shape) (cph/frame-shape? shape) (not (:show-content shape))) From 950fd609173a9c9177d08032d05eeb7a52527197 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 5 Oct 2023 12:40:57 +0200 Subject: [PATCH 3/8] :bug: Fix code generation for areas --- frontend/src/app/util/code_gen/style_css_values.cljs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index a5f1e88345..dae838040e 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -280,9 +280,14 @@ [_ shape _] (:layout-grid-columns shape)) +(defn area-cell? + [{:keys [position area-name]}] + (and (= position :area) (d/not-empty? area-name))) + (defmethod get-value :grid-template-areas [_ shape _] - (when (ctl/grid-layout? shape) + (when (and (ctl/grid-layout? shape) + (some area-cell? (vals (:layout-grid-cells shape)))) (let [result (->> (d/enumerate (:layout-grid-rows shape)) (map From 785b58a6c433a5f7714997771de6019ee2c77905 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 5 Oct 2023 12:55:35 +0200 Subject: [PATCH 4/8] :sparkles: Change behaviour of fill to respect minimum content size --- .../app/common/geom/shapes/flex_layout.cljc | 5 +- .../geom/shapes/flex_layout/bounds.cljc | 38 +- .../geom/shapes/flex_layout/drop_area.cljc | 9 +- .../{lines.cljc => layout_data.cljc} | 102 +++--- .../geom/shapes/flex_layout/modifiers.cljc | 6 +- .../geom/shapes/grid_layout/bounds.cljc | 14 +- .../geom/shapes/grid_layout/layout_data.cljc | 344 +++++++++--------- .../geom/shapes/grid_layout/positions.cljc | 5 +- .../common/geom/shapes/min_size_layout.cljc | 81 +++++ .../src/app/common/geom/shapes/modifiers.cljc | 13 +- frontend/src/app/main/ui/measurements.cljs | 4 +- .../main/ui/shapes/grid_layout_viewer.cljs | 10 +- .../app/main/ui/workspace/viewport/debug.cljs | 36 +- .../viewport/grid_layout_editor.cljs | 4 +- 14 files changed, 402 insertions(+), 269 deletions(-) rename common/src/app/common/geom/shapes/flex_layout/{lines.cljc => layout_data.cljc} (84%) create mode 100644 common/src/app/common/geom/shapes/min_size_layout.cljc diff --git a/common/src/app/common/geom/shapes/flex_layout.cljc b/common/src/app/common/geom/shapes/flex_layout.cljc index 3d196204bf..3be7382da4 100644 --- a/common/src/app/common/geom/shapes/flex_layout.cljc +++ b/common/src/app/common/geom/shapes/flex_layout.cljc @@ -9,7 +9,7 @@ [app.common.data.macros :as dm] [app.common.geom.shapes.flex-layout.bounds :as fbo] [app.common.geom.shapes.flex-layout.drop-area :as fdr] - [app.common.geom.shapes.flex-layout.lines :as fli] + [app.common.geom.shapes.flex-layout.layout-data :as fld] [app.common.geom.shapes.flex-layout.modifiers :as fmo])) (dm/export fbo/layout-content-bounds) @@ -17,6 +17,5 @@ (dm/export fbo/child-layout-bound-points) (dm/export fdr/get-drop-index) (dm/export fdr/get-drop-areas) -(dm/export fli/calc-layout-data) +(dm/export fld/calc-layout-data) (dm/export fmo/layout-child-modifiers) - diff --git a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc index 358dbe34e0..a8a268436d 100644 --- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -11,9 +11,23 @@ [app.common.geom.shapes.points :as gpo] [app.common.types.shape.layout :as ctl])) +;; Setted in app.common.geom.shapes.common-layout +;; We do it this way because circular dependencies +(def -child-min-width nil) + +(defn child-min-width + [child child-bounds bounds objects] + (-child-min-width child child-bounds bounds objects)) + +(def -child-min-height nil) + +(defn child-min-height + [child child-bounds bounds objects] + (-child-min-height child child-bounds bounds objects)) + (defn child-layout-bound-points "Returns the bounds of the children as points" - [parent child parent-bounds child-bounds] + [parent child parent-bounds child-bounds bounds objects] (let [row? (ctl/row? parent) col? (ctl/col? parent) @@ -28,21 +42,13 @@ h-center? (ctl/h-center? parent) h-end? (ctl/h-end? parent) - fill-w? (ctl/fill-width? child) - fill-h? (ctl/fill-height? child) - base-p (gpo/origin child-bounds) width (gpo/width-points child-bounds) height (gpo/height-points child-bounds) - min-width (if fill-w? - (ctl/child-min-width child) - width) - - min-height (if fill-h? - (ctl/child-min-height child) - height) + min-width (child-min-width child child-bounds bounds objects) + min-height (child-min-height child child-bounds bounds objects) ;; This is the leftmost (when row) or topmost (when col) point ;; Will be added always to the bounds and then calculated the other limits @@ -95,19 +101,19 @@ (conj (gpt/subtract base-p (vv min-height)))))) (defn layout-content-points - [bounds parent children] + [bounds parent children objects] (let [parent-id (:id parent) parent-bounds @(get bounds parent-id) get-child-bounds (fn [child] (let [child-id (:id child) - child-bounds @(get bounds child-id) + child-bounds @(get bounds child-id) [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) child-bounds (if (or (ctl/fill-width? child) (ctl/fill-height? child)) - (child-layout-bound-points parent child parent-bounds child-bounds) + (child-layout-bound-points parent child parent-bounds child-bounds bounds objects) child-bounds) child-bounds @@ -122,7 +128,7 @@ (map get-child-bounds)))) (defn layout-content-bounds - [bounds {:keys [layout-padding] :as parent} children] + [bounds {:keys [layout-padding] :as parent} children objects] (let [parent-id (:id parent) parent-bounds @(get bounds parent-id) @@ -153,7 +159,7 @@ pad-left (+ (or pad-left 0) col-pad) layout-points - (layout-content-points bounds parent children)] + (layout-content-points bounds parent children objects)] (if (d/not-empty? layout-points) (-> layout-points diff --git a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc index 8a050b0f04..ce7177ced0 100644 --- a/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/drop_area.cljc @@ -11,7 +11,7 @@ [app.common.geom.point :as gpt] [app.common.geom.rect :as grc] [app.common.geom.shapes.common :as gco] - [app.common.geom.shapes.flex-layout.lines :as fli] + [app.common.geom.shapes.flex-layout.layout-data :as fld] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] [app.common.pages.helpers :as cph] @@ -197,21 +197,22 @@ [shape nil])) (defn get-drop-areas - [frame objects] + [frame objects bounds] (let [[frame modifiers] (get-flip-modifiers frame) children (->> (cph/get-immediate-children objects (:id frame)) (remove :hidden) (map #(cond-> % (some? modifiers) (gtr/transform-shape modifiers))) (map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %))) - layout-data (fli/calc-layout-data frame children (:points frame)) + layout-data (fld/calc-layout-data frame (:points frame) children bounds objects) drop-areas (layout-drop-areas frame layout-data children)] drop-areas)) (defn get-drop-index [frame-id objects position] (let [frame (get objects frame-id) - drop-areas (get-drop-areas frame objects) + bounds (d/lazy-map (keys objects) #(gco/shape->points (get objects %))) + drop-areas (get-drop-areas frame objects bounds) position (gmt/transform-point-center position (gco/shape->center frame) (:transform-inverse frame)) area (d/seek #(grc/contains-point? % position) drop-areas)] (:index area))) diff --git a/common/src/app/common/geom/shapes/flex_layout/lines.cljc b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc similarity index 84% rename from common/src/app/common/geom/shapes/flex_layout/lines.cljc rename to common/src/app/common/geom/shapes/flex_layout/layout_data.cljc index 14b4d110d8..d0cacd31d4 100644 --- a/common/src/app/common/geom/shapes/flex_layout/lines.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/layout_data.cljc @@ -4,7 +4,7 @@ ;; ;; Copyright (c) KALEIDOS INC -(ns app.common.geom.shapes.flex-layout.lines +(ns app.common.geom.shapes.flex-layout.layout-data (:require [app.common.data :as d] [app.common.geom.shapes.flex-layout.positions :as flp] @@ -14,6 +14,20 @@ (def conjv (fnil conj [])) +;; Setted in app.common.geom.shapes.common-layout +;; We do it this way because circular dependencies +(def -child-min-width nil) + +(defn child-min-width + [child child-bounds bounds objects] + (-child-min-width child child-bounds bounds objects)) + +(def -child-min-height nil) + +(defn child-min-height + [child child-bounds bounds objects] + (-child-min-height child child-bounds bounds objects)) + (defn layout-bounds [parent shape-bounds] (let [[pad-top pad-right pad-bottom pad-left] (ctl/paddings parent)] @@ -21,16 +35,17 @@ (defn init-layout-lines "Calculates the lines basic data and accumulated values. The positions will be calculated in a different operation" - [shape children layout-bounds] + [shape children layout-bounds bounds objects auto?] (let [col? (ctl/col? shape) row? (ctl/row? shape) space-around? (ctl/space-around? shape) space-evenly? (ctl/space-evenly? shape) - wrap? (and (ctl/wrap? shape) - (or col? (not (ctl/auto-width? shape))) - (or row? (not (ctl/auto-height? shape)))) + auto-width? (or (ctl/auto-width? shape) auto?) + auto-height? (or (ctl/auto-height? shape) auto?) + + wrap? (and (ctl/wrap? shape) (or col? (not auto-width?)) (or row? (not auto-height?))) [layout-gap-row layout-gap-col] (ctl/gaps shape) @@ -52,8 +67,6 @@ child-width (gpo/width-points child-bounds) child-height (gpo/height-points child-bounds) - child-min-width (ctl/child-min-width child) - child-min-height (ctl/child-min-height child) child-max-width (ctl/child-max-width child) child-max-height (ctl/child-max-height child) @@ -68,15 +81,15 @@ ;; We need this info later to calculate the child resizes when fill child-data {:id (:id child) - :child-min-width (if fill-width? child-min-width child-width) - :child-min-height (if fill-height? child-min-height child-height) + :child-min-width (child-min-width child child-bounds bounds objects) + :child-min-height (child-min-height child child-bounds bounds objects) :child-max-width (if fill-width? child-max-width child-width) :child-max-height (if fill-height? child-max-height child-height)} - next-min-width (+ child-margin-width (if fill-width? child-min-width child-width)) - next-min-height (+ child-margin-height (if fill-height? child-min-height child-height)) - next-max-width (+ child-margin-width (if fill-width? child-max-width child-width)) - next-max-height (+ child-margin-height (if fill-height? child-max-height child-height)) + next-min-width (+ child-margin-width (:child-min-width child-data)) + next-min-height (+ child-margin-height (:child-min-height child-data)) + next-max-width (+ child-margin-width (:child-max-width child-data)) + next-max-height (+ child-margin-height (:child-max-height child-data)) total-gap-col (cond space-evenly? @@ -160,11 +173,11 @@ (recur remainder items)))))) (defn add-lines-positions - [parent layout-bounds layout-lines] + [parent layout-bounds auto? layout-lines] (let [row? (ctl/row? parent) col? (ctl/col? parent) - auto-width? (ctl/auto-width? parent) - auto-height? (ctl/auto-height? parent) + auto-width? (or (ctl/auto-width? parent) auto?) + auto-height? (or (ctl/auto-height? parent) auto?) space-evenly? (ctl/space-evenly? parent) space-around? (ctl/space-around? parent) @@ -178,7 +191,7 @@ [(+ total-width line-width) (+ total-height line-height)]) (add-ranges [[total-min-width total-min-height total-max-width total-max-height] - {:keys [line-min-width line-min-height line-max-width line-max-height]}] + {:keys [line-min-width line-min-height line-max-width line-max-height]}] [(+ total-min-width line-min-width) (+ total-min-height line-min-height) (+ total-max-width line-max-width) @@ -238,32 +251,32 @@ (cond->> layout-lines row? (map #(assoc % :line-width - (if (ctl/auto-width? parent) + (if auto-width? (:line-min-width %) (max (:line-min-width %) (min (get-layout-width %) (:line-max-width %)))))) col? (map #(assoc % :line-height - (if (ctl/auto-height? parent) + (if auto-height? (:line-min-height %) (max (:line-min-height %) (min (get-layout-height %) (:line-max-height %)))))) - (and row? (or (>= total-min-height rest-layout-height) (ctl/auto-height? parent))) + (and row? (or (>= total-min-height rest-layout-height) auto-height?)) (map #(assoc % :line-height (:line-min-height %))) - (and row? (<= total-max-height rest-layout-height) (not (ctl/auto-height? parent))) + (and row? (<= total-max-height rest-layout-height) (not auto-height?)) (map #(assoc % :line-height (+ (:line-max-height %) stretch-height-fix))) - (and row? (< total-min-height rest-layout-height total-max-height) (not (ctl/auto-height? parent))) + (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) (ctl/auto-width? parent))) + (and col? (or (>= total-min-width rest-layout-width) auto-width?)) (map #(assoc % :line-width (:line-min-width %))) - (and col? (<= total-max-width rest-layout-width) (not (ctl/auto-width? parent))) + (and col? (<= total-max-width rest-layout-width) (not auto-width?)) (map #(assoc % :line-width (+ (:line-max-width %) stretch-width-fix))) - (and col? (< total-min-width rest-layout-width total-max-width) (not (ctl/auto-width? parent))) + (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)) ;; Add information to limit the growth of width: 100% shapes to the bounds of the layout @@ -298,15 +311,15 @@ (defn add-line-spacing "Calculates the baseline for a flex layout" - [shape layout-bounds {:keys [num-children line-width line-height] :as line-data}] + [shape layout-bounds auto? {:keys [num-children line-width line-height] :as line-data}] (let [width (gpo/width-points layout-bounds) height (gpo/height-points layout-bounds) row? (ctl/row? shape) col? (ctl/col? shape) - auto-height? (ctl/auto-height? shape) - auto-width? (ctl/auto-width? shape) + auto-height? (or (ctl/auto-height? shape) auto?) + auto-width? (or (ctl/auto-width? shape) auto?) space-between? (ctl/space-between? shape) space-evenly? (ctl/space-evenly? shape) space-around? (ctl/space-around? shape) @@ -402,22 +415,25 @@ (defn calc-layout-data "Digest the layout data to pass it to the constrains" - [shape children shape-bounds] + ([shape shape-bounds children bounds objects] + (calc-layout-data shape shape-bounds children bounds objects false)) - (let [layout-bounds (layout-bounds shape shape-bounds) - reverse? (ctl/reverse? shape) - children (cond->> children (not reverse?) reverse) + ([shape shape-bounds children bounds objects auto?] - ;; Don't take into account absolute children - children (->> children (remove (comp ctl/layout-absolute? second))) + (let [layout-bounds (layout-bounds shape shape-bounds) + reverse? (ctl/reverse? shape) + children (cond->> children (not reverse?) reverse) - ;; Creates the layout lines information - layout-lines - (->> (init-layout-lines shape children layout-bounds) - (add-lines-positions shape layout-bounds) - (into [] (comp (map (partial add-line-spacing shape layout-bounds)) - (map (partial add-children-resizes shape)))))] + ;; Don't take into account absolute children + children (->> children (remove (comp ctl/layout-absolute? second))) - {:layout-lines layout-lines - :layout-bounds layout-bounds - :reverse? reverse?})) + ;; Creates the layout lines information + layout-lines + (->> (init-layout-lines shape children layout-bounds bounds objects auto?) + (add-lines-positions shape layout-bounds auto?) + (into [] (comp (map (partial add-line-spacing shape layout-bounds auto?)) + (map (partial add-children-resizes shape)))))] + + {:layout-lines layout-lines + :layout-bounds layout-bounds + :reverse? reverse?}))) diff --git a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc index 7f0d5ee5b4..4d95c38c47 100644 --- a/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/modifiers.cljc @@ -34,7 +34,8 @@ (let [line-width (min line-width (or to-bound-width line-width)) target-width (max (- line-width (ctl/child-width-margin child)) 0.01) max-width (max (ctl/child-max-width child) 0.01) - target-width (mth/clamp target-width (ctl/child-min-width child) max-width) + child-min-width (get-in children-data [(:id child) :child-min-width]) + target-width (mth/clamp target-width child-min-width max-width) fill-scale (/ target-width child-width)] {:width target-width :modifiers (ctm/resize-modifiers (gpt/point fill-scale 1) child-origin transform transform-inverse)}))) @@ -58,7 +59,8 @@ (let [line-height (min line-height (or to-bound-height line-height)) target-height (max (- line-height (ctl/child-height-margin child)) 0.01) max-height (max (ctl/child-max-height child) 0.01) - target-height (mth/clamp target-height (ctl/child-min-height child) max-height) + child-min-height (get-in children-data [(:id child) :child-min-height]) + target-height (mth/clamp target-height child-min-height max-height) fill-scale (/ target-height child-height)] {:height target-height :modifiers (ctm/resize-modifiers (gpt/point 1 fill-scale) child-origin transform transform-inverse)}))) diff --git a/common/src/app/common/geom/shapes/grid_layout/bounds.cljc b/common/src/app/common/geom/shapes/grid_layout/bounds.cljc index 57ee718682..6f1b0d3f2c 100644 --- a/common/src/app/common/geom/shapes/grid_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/bounds.cljc @@ -8,21 +8,15 @@ (:require [app.common.data :as d] [app.common.geom.point :as gpt] - [app.common.geom.shapes.grid-layout.layout-data :as ld] [app.common.geom.shapes.points :as gpo])) (defn layout-content-points - [bounds parent children] + [bounds parent {:keys [row-tracks column-tracks]}] (let [parent-id (:id parent) parent-bounds @(get bounds parent-id) hv #(gpo/start-hv parent-bounds %) - vv #(gpo/start-vv parent-bounds %) - - children (->> children - (map #(vector @(get bounds (:id %)) %))) - - {:keys [row-tracks column-tracks]} (ld/calc-layout-data parent children parent-bounds)] + vv #(gpo/start-vv parent-bounds %)] (d/concat-vec (->> row-tracks (mapcat #(vector (:start-p %) @@ -32,7 +26,7 @@ (gpt/add (:start-p %) (hv (:size %))))))))) (defn layout-content-bounds - [bounds {:keys [layout-padding] :as parent} children] + [bounds {:keys [layout-padding] :as parent} layout-data] (let [parent-id (:id parent) parent-bounds @(get bounds parent-id) @@ -43,7 +37,7 @@ pad-bottom (or pad-bottom 0) pad-left (or pad-left 0) - layout-points (layout-content-points bounds parent children)] + layout-points (layout-content-points bounds parent layout-data)] (if (d/not-empty? layout-points) (-> layout-points diff --git a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc index 5e3595ee20..881bf1c8e8 100644 --- a/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/layout_data.cljc @@ -55,25 +55,25 @@ [app.common.math :as mth] [app.common.types.shape.layout :as ctl])) +;; Setted in app.common.geom.shapes.common-layout +;; We do it this way because circular dependencies +(def -child-min-width nil) + +(defn child-min-width + [child child-bounds bounds objects] + (-child-min-width child child-bounds bounds objects)) + +(def -child-min-height nil) + +(defn child-min-height + [child child-bounds bounds objects] + (-child-min-height child child-bounds bounds objects)) + (defn layout-bounds [parent shape-bounds] (let [[pad-top pad-right pad-bottom pad-left] (ctl/paddings parent)] (gpo/pad-points shape-bounds pad-top pad-right pad-bottom pad-left))) -(defn child-min-width - [child bounds] - (+ (if (ctl/fill-width? child) - (ctl/child-min-width child) - (gpo/width-points bounds)) - (ctl/child-width-margin child))) - -(defn child-min-height - [child bounds] - (+ (if (ctl/fill-height? child) - (ctl/child-min-height child) - (gpo/height-points bounds)) - (ctl/child-height-margin child))) - (defn calculate-initial-track-size [total-value {:keys [type value] :as track}] @@ -91,12 +91,12 @@ (assoc track :size size :max-size max-size))) (defn set-auto-base-size - [track-list children shape-cells type] + [track-list children shape-cells bounds objects type] (let [[prop prop-span size-fn] (if (= type :column) - [:column :column-span child-min-width] - [:row :row-span child-min-height])] + [:column :column-span child-min-width] + [:row :row-span child-min-height])] (reduce (fn [tracks [child-bounds child-shape]] (let [cell (get shape-cells (:id child-shape)) @@ -105,7 +105,7 @@ (cond-> tracks (and (= (get cell prop-span) 1) (contains? #{:flex :auto} (:type track))) - (update-in [idx :size] max (size-fn child-shape child-bounds))))) + (update-in [idx :size] max (size-fn child-shape child-bounds bounds objects))))) track-list children))) @@ -216,14 +216,14 @@ (some? (->> tracks (d/seek #(= :flex (:type %))))))) (defn size-to-allocate - [type parent [child-bounds child] cell] + [type parent [child-bounds child] cell bounds objects] (let [[row-gap column-gap] (ctl/gaps parent) [sfn gap prop-span] (if (= type :column) [child-min-width column-gap :column-span] [child-min-height row-gap :row-span]) span (get cell prop-span)] - (- (sfn child child-bounds) (* gap (dec span))))) + (- (sfn child child-bounds bounds objects) (* gap (dec span))))) (defn allocate-auto-tracks [allocations indexed-tracks to-allocate] @@ -271,7 +271,7 @@ fr-value)))) (defn set-auto-multi-span - [parent track-list children-map shape-cells type] + [parent track-list children-map shape-cells bounds objects type] (let [[prop prop-span] (if (= type :column) @@ -293,7 +293,7 @@ to-idx (+ (dec (get cell prop)) (get cell prop-span)) indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx) - to-allocate (size-to-allocate type parent (get children-map shape-id) cell) + to-allocate (size-to-allocate type parent (get children-map shape-id) cell bounds objects) ;; Remove the size and the tracks that are not allocated [to-allocate indexed-tracks] @@ -307,10 +307,9 @@ [(- to-allocate (:size track)) result])) [to-allocate []])) - non-assigned-indexed-tracks (->> indexed-tracks - (remove (fn [[idx track]] (contains? allocated idx)))) + (remove (fn [[idx _]] (contains? allocated idx)))) ;; First we try to assign into the non-assigned tracks [allocated to-allocate] @@ -331,7 +330,7 @@ track-list)) (defn set-flex-multi-span - [parent track-list children-map shape-cells type] + [parent track-list children-map shape-cells bounds objects type] (let [[prop prop-span] (if (= type :column) @@ -352,7 +351,7 @@ to-idx (+ (dec (get cell prop)) (get cell prop-span)) indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx) - to-allocate (size-to-allocate type parent (get children-map shape-id) cell) + to-allocate (size-to-allocate type parent (get children-map shape-id) cell bounds objects) ;; Remove the size and the tracks that are not allocated [to-allocate total-frs indexed-tracks] @@ -390,197 +389,202 @@ (recur (rest tracks) min-fr))))) (defn calc-layout-data - [parent children transformed-parent-bounds] + ([parent transformed-parent-bounds children bounds objects] + (calc-layout-data parent transformed-parent-bounds children bounds objects false)) - (let [hv #(gpo/start-hv transformed-parent-bounds %) - vv #(gpo/start-vv transformed-parent-bounds %) + ([parent transformed-parent-bounds children bounds objects auto?] + (let [hv #(gpo/start-hv transformed-parent-bounds %) + vv #(gpo/start-vv transformed-parent-bounds %) - layout-bounds (layout-bounds parent transformed-parent-bounds) + layout-bounds (layout-bounds parent transformed-parent-bounds) - bound-height (gpo/height-points layout-bounds) - bound-width (gpo/width-points layout-bounds) - bound-corner (gpo/origin layout-bounds) + bound-height (gpo/height-points layout-bounds) + bound-width (gpo/width-points layout-bounds) + bound-corner (gpo/origin layout-bounds) - [row-gap column-gap] (ctl/gaps parent) - auto-height? (ctl/auto-height? parent) - auto-width? (ctl/auto-width? parent) + [row-gap column-gap] (ctl/gaps parent) + auto-height? (or (ctl/auto-height? parent) auto?) + auto-width? (or (ctl/auto-width? parent) auto?) - {:keys [layout-grid-columns layout-grid-rows layout-grid-cells]} parent - num-columns (count layout-grid-columns) - num-rows (count layout-grid-rows) + {:keys [layout-grid-columns layout-grid-rows layout-grid-cells]} parent + num-columns (count layout-grid-columns) + num-rows (count layout-grid-rows) - column-total-gap (* column-gap (dec num-columns)) - row-total-gap (* row-gap (dec num-rows)) + column-total-gap (* column-gap (dec num-columns)) + row-total-gap (* row-gap (dec num-rows)) - ;; Map shape->cell - shape-cells - (into {} - (mapcat (fn [[_ cell]] - (->> (:shapes cell) (map #(vector % cell))))) - layout-grid-cells) + ;; Map shape->cell + shape-cells + (into {} + (mapcat (fn [[_ cell]] + (->> (:shapes cell) (map #(vector % cell))))) + layout-grid-cells) - children (->> children (remove #(ctl/layout-absolute? (second %)))) - children-map - (into {} - (map #(vector (:id (second %)) %)) - children) + children + (->> children + (remove #(ctl/layout-absolute? (second %)))) - ;; Initialize tracks - column-tracks - (->> layout-grid-columns - (mapv (partial calculate-initial-track-size bound-width))) + children-map + (into {} + (map #(vector (:id (second %)) %)) + children) - row-tracks - (->> layout-grid-rows - (mapv (partial calculate-initial-track-size bound-height))) + ;; Initialize tracks + column-tracks + (->> layout-grid-columns + (mapv (partial calculate-initial-track-size bound-width))) - ;; Go through cells to adjust auto sizes for span=1. Base is the max of its children - column-tracks (set-auto-base-size column-tracks children shape-cells :column) - row-tracks (set-auto-base-size row-tracks children shape-cells :row) + row-tracks + (->> layout-grid-rows + (mapv (partial calculate-initial-track-size bound-height))) - ;; Adjust multi-spaned cells with no flex columns - column-tracks (set-auto-multi-span parent column-tracks children-map shape-cells :column) - row-tracks (set-auto-multi-span parent row-tracks children-map shape-cells :row) + ;; Go through cells to adjust auto sizes for span=1. Base is the max of its children + column-tracks (set-auto-base-size column-tracks children shape-cells bounds objects :column) + row-tracks (set-auto-base-size row-tracks children shape-cells bounds objects :row) - ;; Calculate the `fr` unit and adjust the size - column-total-size-nofr (tracks-total-size (->> column-tracks (remove #(= :flex (:type %))))) - row-total-size-nofr (tracks-total-size (->> row-tracks (remove #(= :flex (:type %))))) + ;; Adjust multi-spaned cells with no flex columns + column-tracks (set-auto-multi-span parent column-tracks children-map shape-cells bounds objects :column) + row-tracks (set-auto-multi-span parent row-tracks children-map shape-cells bounds objects :row) - column-frs (tracks-total-frs column-tracks) - row-frs (tracks-total-frs row-tracks) + ;; Calculate the `fr` unit and adjust the size + column-total-size-nofr (tracks-total-size (->> column-tracks (remove #(= :flex (:type %))))) + row-total-size-nofr (tracks-total-size (->> row-tracks (remove #(= :flex (:type %))))) - ;; Assign minimum size to the multi-span flex tracks. We do this after calculating - ;; the fr size because will affect only the minimum. The maximum will be set by the - ;; fracion - column-tracks (set-flex-multi-span parent column-tracks children-map shape-cells :column) - row-tracks (set-flex-multi-span parent row-tracks children-map shape-cells :row) + column-frs (tracks-total-frs column-tracks) + row-frs (tracks-total-frs row-tracks) - ;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size - free-column-space (max 0 (- bound-width (+ column-total-size-nofr column-total-gap))) - free-row-space (max 0 (- bound-height (+ row-total-size-nofr row-total-gap))) + ;; Assign minimum size to the multi-span flex tracks. We do this after calculating + ;; the fr size because will affect only the minimum. The maximum will be set by the + ;; fracion + column-tracks (set-flex-multi-span parent column-tracks children-map shape-cells bounds objects :column) + row-tracks (set-flex-multi-span parent row-tracks children-map shape-cells bounds objects :row) - ;; Get the minimum values for fr's - min-column-fr (min-fr-value column-tracks) - min-row-fr (min-fr-value row-tracks) + ;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size + free-column-space (max 0 (- bound-width (+ column-total-size-nofr column-total-gap))) + free-row-space (max 0 (- bound-height (+ row-total-size-nofr row-total-gap))) - column-fr (if auto-width? min-column-fr (mth/finite (/ free-column-space column-frs) 0)) - row-fr (if auto-height? min-row-fr (mth/finite (/ free-row-space row-frs) 0)) + ;; Get the minimum values for fr's + min-column-fr (min-fr-value column-tracks) + min-row-fr (min-fr-value row-tracks) - column-tracks (set-fr-value column-tracks column-fr auto-width?) - row-tracks (set-fr-value row-tracks row-fr auto-height?) + column-fr (if auto-width? min-column-fr (mth/finite (/ free-column-space column-frs) 0)) + row-fr (if auto-height? min-row-fr (mth/finite (/ free-row-space row-frs) 0)) - ;; Distribute free space between `auto` tracks - column-total-size (tracks-total-size column-tracks) - row-total-size (tracks-total-size row-tracks) + column-tracks (set-fr-value column-tracks column-fr auto-width?) + row-tracks (set-fr-value row-tracks row-fr auto-height?) - free-column-space (max 0 (if auto-width? 0 (- bound-width (+ column-total-size column-total-gap)))) - free-row-space (max 0 (if auto-height? 0 (- bound-height (+ row-total-size row-total-gap)))) - column-autos (tracks-total-autos column-tracks) - row-autos (tracks-total-autos row-tracks) + ;; Distribute free space between `auto` tracks + column-total-size (tracks-total-size column-tracks) + row-total-size (tracks-total-size row-tracks) - column-add-auto (/ free-column-space column-autos) - row-add-auto (/ free-row-space row-autos) + free-column-space (max 0 (if auto-width? 0 (- bound-width (+ column-total-size column-total-gap)))) + free-row-space (max 0 (if auto-height? 0 (- bound-height (+ row-total-size row-total-gap)))) + column-autos (tracks-total-autos column-tracks) + row-autos (tracks-total-autos row-tracks) - column-tracks (cond-> column-tracks - (= :stretch (:layout-justify-content parent)) - (add-auto-size column-add-auto)) + column-add-auto (/ free-column-space column-autos) + row-add-auto (/ free-row-space row-autos) - row-tracks (cond-> row-tracks - (= :stretch (:layout-align-content parent)) - (add-auto-size row-add-auto)) + column-tracks (cond-> column-tracks + (= :stretch (:layout-justify-content parent)) + (add-auto-size column-add-auto)) - column-total-size (tracks-total-size column-tracks) - row-total-size (tracks-total-size row-tracks) + row-tracks (cond-> row-tracks + (= :stretch (:layout-align-content parent)) + (add-auto-size row-add-auto)) - num-columns (count column-tracks) - column-gap - (case (:layout-justify-content parent) - auto-width? - column-gap + column-total-size (tracks-total-size column-tracks) + row-total-size (tracks-total-size row-tracks) - :space-evenly - (max column-gap (/ (- bound-width column-total-size) (inc num-columns))) + num-columns (count column-tracks) + column-gap + (case (:layout-justify-content parent) + auto-width? + column-gap - :space-around - (max column-gap (/ (- bound-width column-total-size) num-columns)) + :space-evenly + (max column-gap (/ (- bound-width column-total-size) (inc num-columns))) - :space-between - (max column-gap (if (= num-columns 1) column-gap (/ (- bound-width column-total-size) (dec num-columns)))) + :space-around + (max column-gap (/ (- bound-width column-total-size) num-columns)) - column-gap) + :space-between + (max column-gap (if (= num-columns 1) column-gap (/ (- bound-width column-total-size) (dec num-columns)))) - num-rows (count row-tracks) - row-gap - (case (:layout-align-content parent) - auto-height? - row-gap + column-gap) - :space-evenly - (max row-gap (/ (- bound-height row-total-size) (inc num-rows))) + num-rows (count row-tracks) + row-gap + (case (:layout-align-content parent) + auto-height? + row-gap - :space-around - (max row-gap (/ (- bound-height row-total-size) num-rows)) + :space-evenly + (max row-gap (/ (- bound-height row-total-size) (inc num-rows))) - :space-between - (max row-gap (if (= num-rows 1) row-gap (/ (- bound-height row-total-size) (dec num-rows)))) + :space-around + (max row-gap (/ (- bound-height row-total-size) num-rows)) - row-gap) + :space-between + (max row-gap (if (= num-rows 1) row-gap (/ (- bound-height row-total-size) (dec num-rows)))) - start-p - (cond-> bound-corner - (and (not auto-width?) (= :end (:layout-justify-content parent))) - (gpt/add (hv (- bound-width (+ column-total-size column-total-gap)))) + row-gap) - (and (not auto-width?) (= :center (:layout-justify-content parent))) - (gpt/add (hv (/ (- bound-width (+ column-total-size column-total-gap)) 2))) + start-p + (cond-> bound-corner + (and (not auto-width?) (= :end (:layout-justify-content parent))) + (gpt/add (hv (- bound-width (+ column-total-size column-total-gap)))) - (and (not auto-height?) (= :end (:layout-align-content parent))) - (gpt/add (vv (- bound-height (+ row-total-size row-total-gap)))) + (and (not auto-width?) (= :center (:layout-justify-content parent))) + (gpt/add (hv (/ (- bound-width (+ column-total-size column-total-gap)) 2))) - (and (not auto-height?) (= :center (:layout-align-content parent))) - (gpt/add (vv (/ (- bound-height (+ row-total-size row-total-gap)) 2))) + (and (not auto-height?) (= :end (:layout-align-content parent))) + (gpt/add (vv (- bound-height (+ row-total-size row-total-gap)))) - (and (not auto-width?) (= :space-around (:layout-justify-content parent))) - (gpt/add (hv (/ column-gap 2))) + (and (not auto-height?) (= :center (:layout-align-content parent))) + (gpt/add (vv (/ (- bound-height (+ row-total-size row-total-gap)) 2))) - (and (not auto-width?) (= :space-evenly (:layout-justify-content parent))) - (gpt/add (hv column-gap)) + (and (not auto-width?) (= :space-around (:layout-justify-content parent))) + (gpt/add (hv (/ column-gap 2))) - (and (not auto-height?) (= :space-around (:layout-align-content parent))) - (gpt/add (vv (/ row-gap 2))) + (and (not auto-width?) (= :space-evenly (:layout-justify-content parent))) + (gpt/add (hv column-gap)) - (and (not auto-height?) (= :space-evenly (:layout-align-content parent))) - (gpt/add (vv row-gap))) + (and (not auto-height?) (= :space-around (:layout-align-content parent))) + (gpt/add (vv (/ row-gap 2))) - column-tracks - (->> column-tracks - (reduce (fn [[tracks start-p] {:keys [size] :as track}] - [(conj tracks (assoc track :start-p start-p)) - (gpt/add start-p (hv (+ size column-gap)))]) - [[] start-p]) - (first)) + (and (not auto-height?) (= :space-evenly (:layout-align-content parent))) + (gpt/add (vv row-gap))) - row-tracks - (->> row-tracks - (reduce (fn [[tracks start-p] {:keys [size] :as track}] - [(conj tracks (assoc track :start-p start-p)) - (gpt/add start-p (vv (+ size row-gap)))]) - [[] start-p]) - (first))] + column-tracks + (->> column-tracks + (reduce (fn [[tracks start-p] {:keys [size] :as track}] + [(conj tracks (assoc track :start-p start-p)) + (gpt/add start-p (hv (+ size column-gap)))]) + [[] start-p]) + (first)) - {:origin start-p - :layout-bounds layout-bounds - :row-tracks row-tracks - :column-tracks column-tracks - :shape-cells shape-cells - :column-gap column-gap - :row-gap row-gap + row-tracks + (->> row-tracks + (reduce (fn [[tracks start-p] {:keys [size] :as track}] + [(conj tracks (assoc track :start-p start-p)) + (gpt/add start-p (vv (+ size row-gap)))]) + [[] start-p]) + (first))] - ;; Convenient informaton for visualization - :column-total-size column-total-size - :column-total-gap column-total-gap - :row-total-size row-total-size - :row-total-gap row-total-gap})) + {:origin start-p + :layout-bounds layout-bounds + :row-tracks row-tracks + :column-tracks column-tracks + :shape-cells shape-cells + :column-gap column-gap + :row-gap row-gap + + ;; Convenient informaton for visualization + :column-total-size column-total-size + :column-total-gap column-total-gap + :row-total-size row-total-size + :row-total-gap row-total-gap}))) (defn get-cell-data [{:keys [origin row-tracks column-tracks shape-cells]} _transformed-parent-bounds [_ child]] diff --git a/common/src/app/common/geom/shapes/grid_layout/positions.cljc b/common/src/app/common/geom/shapes/grid_layout/positions.cljc index 435d662187..eb76956153 100644 --- a/common/src/app/common/geom/shapes/grid_layout/positions.cljc +++ b/common/src/app/common/geom/shapes/grid_layout/positions.cljc @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.point :as gpt] + [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.grid-layout.layout-data :as ld] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] @@ -254,6 +255,8 @@ children (->> (cph/get-immediate-children objects (:id frame)) (remove :hidden) (map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %))) - layout-data (ld/calc-layout-data frame children (:points frame))] + + bounds (d/lazy-map (keys objects) #(gco/shape->points (get objects %))) + layout-data (ld/calc-layout-data frame (:points frame) children bounds objects)] (get-position-grid-coord layout-data position))) diff --git a/common/src/app/common/geom/shapes/min_size_layout.cljc b/common/src/app/common/geom/shapes/min_size_layout.cljc new file mode 100644 index 0000000000..7bd3b088a2 --- /dev/null +++ b/common/src/app/common/geom/shapes/min_size_layout.cljc @@ -0,0 +1,81 @@ +;; 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.min-size-layout + (:require + [app.common.data :as d] + [app.common.geom.shapes.common :as gco] + [app.common.geom.shapes.flex-layout.bounds :as fb] + [app.common.geom.shapes.flex-layout.layout-data :as fd] + [app.common.geom.shapes.grid-layout.bounds :as gb] + [app.common.geom.shapes.grid-layout.layout-data :as gd] + [app.common.geom.shapes.points :as gpo] + [app.common.pages.helpers :as cph] + [app.common.types.shape.layout :as ctl])) + +(defn child-min-width + [child child-bounds bounds objects] + (let [min-width + (cond + (and (ctl/fill-width? child) + (ctl/flex-layout? child)) + (gpo/width-points (fb/layout-content-bounds bounds child (->> child :shapes (map (d/getf objects))) objects)) + + (and (ctl/fill-width? child) + (ctl/grid-layout? child)) + (let [children + (->> (cph/get-immediate-children objects (:id child)) + (remove :hidden) + (remove gco/invalid-geometry?) + (map (fn [child] [@(get bounds (:id child)) child]))) + layout-data (gd/calc-layout-data child @(get bounds (:id child)) children bounds objects true)] + (gpo/width-points (gb/layout-content-bounds bounds child layout-data))) + + (ctl/fill-width? child) + (ctl/child-min-width child) + + :else + (gpo/width-points child-bounds))] + (+ min-width (ctl/child-width-margin child)))) + +(defn child-min-height + [child child-bounds bounds objects] + (let [min-height + (cond + (and (ctl/fill-height? child) (ctl/flex-layout? child)) + (gpo/height-points (fb/layout-content-bounds bounds child (->> child :shapes (map (d/getf objects))) objects)) + + (and (ctl/fill-height? child) (ctl/grid-layout? child)) + (let [children (->> child :shapes + (map (d/getf objects)) + (map (fn [child] [@(get bounds (:id child)) child]))) + layout-data (gd/calc-layout-data child (:points child) children bounds objects true) + auto-bounds (gb/layout-content-bounds bounds child layout-data)] + (gpo/height-points auto-bounds)) + + (ctl/fill-height? child) + (ctl/child-min-height child) + + :else + (gpo/height-points child-bounds))] + (+ min-height (ctl/child-height-margin child)))) + +#?(:cljs + (do (set! fd/-child-min-width child-min-width) + (set! fd/-child-min-height child-min-height) + (set! fb/-child-min-width child-min-width) + (set! fb/-child-min-height child-min-height) + (set! gd/-child-min-width child-min-width) + (set! gd/-child-min-height child-min-height)) + + :clj + (do (alter-var-root #'fd/-child-min-width (constantly child-min-width)) + (alter-var-root #'fd/-child-min-height (constantly child-min-height)) + (alter-var-root #'fb/-child-min-width (constantly child-min-width)) + (alter-var-root #'fb/-child-min-height (constantly child-min-height)) + (alter-var-root #'gd/-child-min-width (constantly child-min-width)) + (alter-var-root #'gd/-child-min-height (constantly child-min-height)))) + diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index b87f93593c..c082e9ab9d 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -13,6 +13,7 @@ [app.common.geom.shapes.constraints :as gct] [app.common.geom.shapes.flex-layout :as gcfl] [app.common.geom.shapes.grid-layout :as gcgl] + [app.common.geom.shapes.min-size-layout] [app.common.geom.shapes.pixel-precision :as gpp] [app.common.geom.shapes.points :as gpo] [app.common.geom.shapes.transforms :as gtr] @@ -181,7 +182,8 @@ (remove :hidden) (remove gco/invalid-geometry?) (map apply-modifiers)) - layout-data (gcfl/calc-layout-data parent children @transformed-parent-bounds) + + layout-data (gcfl/calc-layout-data parent @transformed-parent-bounds children bounds objects) children (into [] (cond-> children (not (:reverse? layout-data)) reverse)) max-idx (dec (count children)) layout-lines (:layout-lines layout-data)] @@ -220,7 +222,7 @@ (remove :hidden) (remove gco/invalid-geometry?) (map apply-modifiers)) - grid-data (gcgl/calc-layout-data parent children @transformed-parent-bounds)] + grid-data (gcgl/calc-layout-data parent @transformed-parent-bounds children bounds objects)] (loop [modif-tree modif-tree bound+child (first children) pending (rest children)] @@ -260,10 +262,13 @@ (when (and (d/not-empty? children) (or (ctl/auto-height? parent) (ctl/auto-width? parent))) (cond (ctl/flex-layout? parent) - (gcfl/layout-content-bounds bounds parent children) + (gcfl/layout-content-bounds bounds parent children objects) (ctl/grid-layout? parent) - (gcgl/layout-content-bounds bounds parent children))) + (let [children (->> children + (map (fn [child] [@(get bounds (:id child)) child]))) + layout-data (gcgl/calc-layout-data parent @parent-bounds children bounds objects)] + (gcgl/layout-content-bounds bounds parent layout-data)))) auto-width (when content-bounds (gpo/width-points content-bounds)) auto-height (when content-bounds (gpo/height-points content-bounds))] diff --git a/frontend/src/app/main/ui/measurements.cljs b/frontend/src/app/main/ui/measurements.cljs index 5a47afa4ba..9643580b9c 100644 --- a/frontend/src/app/main/ui/measurements.cljs +++ b/frontend/src/app/main/ui/measurements.cljs @@ -706,7 +706,9 @@ wrap-blocks (let [block-children (->> children (map #(vector (gpo/parent-coords-bounds (:points %) (:points frame)) %))) - layout-data (gsl/calc-layout-data frame block-children (:points frame)) + bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) + + layout-data (gsl/calc-layout-data frame (:points frame) block-children bounds objects) layout-bounds (:layout-bounds layout-data) xv #(gpo/start-hv layout-bounds %) yv #(gpo/start-vv layout-bounds %)] diff --git a/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs b/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs index 6f7373cda2..ee6b500676 100644 --- a/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs +++ b/frontend/src/app/main/ui/shapes/grid_layout_viewer.cljs @@ -6,13 +6,16 @@ (ns app.main.ui.shapes.grid-layout-viewer (:require + [app.common.data :as d] [app.common.data.macros :as dm] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.geom.shapes.grid-layout :as gsg] [app.common.geom.shapes.points :as gpo] + [app.common.pages.helpers :as cph] [app.common.types.shape.layout :as ctl] + [app.main.refs :as refs] [rumext.v2 :as mf])) (mf/defc grid-cell-area-label @@ -82,14 +85,15 @@ {::mf/wrap-props false} [props] (let [shape (unchecked-get props "shape") - childs (unchecked-get props "childs") + objects (mf/deref refs/workspace-page-objects) + bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) children - (->> childs + (->> (cph/get-immediate-children objects (:id shape)) (remove :hidden) (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %))) - layout-data (gsg/calc-layout-data shape children (:points shape))] + layout-data (gsg/calc-layout-data shape (:points shape) children bounds objects)] [:g.cells (for [cell (ctl/get-cells shape {:sort? true})] diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 67116f6244..0e870a2751 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -40,18 +40,23 @@ (let [children (->> (cph/get-immediate-children objects (:id shape)) (remove :hidden)) bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points])) + + grid-layout-data + (when (ctl/grid-layout? shape) + (gsg/calc-layout-data shape (:points shape) children bounds objects)) + layout-bounds (cond (ctl/flex-layout? shape) - (gsl/layout-content-bounds bounds shape children) + (gsl/layout-content-bounds bounds shape children objects) (ctl/grid-layout? shape) - (gsg/layout-content-bounds bounds shape children)) + (gsg/layout-content-bounds bounds shape grid-layout-data)) layout-points (cond (ctl/flex-layout? shape) - (flatten (gsl/layout-content-points bounds shape children)) + (flatten (gsl/layout-content-points bounds shape children objects)) (ctl/grid-layout? shape) - (flatten (gsg/layout-content-points bounds shape children)))] + (flatten (gsg/layout-content-points bounds shape grid-layout-data)))] [:g.debug-layout {:pointer-events "none"} [:polygon {:points (->> layout-bounds (map #(dm/fmt "%, %" (:x %) (:y %))) (str/join " ")) @@ -87,7 +92,10 @@ children (->> (cph/get-immediate-children objects (:id shape)) (remove :hidden) (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %))) - layout-data (gsl/calc-layout-data shape children (:points shape)) + + bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points])) + + layout-data (gsl/calc-layout-data shape (:points shape) children bounds objects) layout-bounds (:layout-bounds layout-data) xv #(gpo/start-hv layout-bounds %) @@ -121,10 +129,12 @@ (when (and (= (count selected-shapes) 1) (= :frame (-> selected-shapes first :type))) (first selected-shapes)) - shape (or selected-frame (get objects hover-top-frame-id))] + shape (or selected-frame (get objects hover-top-frame-id)) + + bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points]))] (when (and shape (:layout shape)) - (let [drop-areas (gsl/get-drop-areas shape objects)] + (let [drop-areas (gsl/get-drop-areas shape objects bounds)] [:g.debug-layout {:pointer-events "none" :transform (gsh/transform-str shape)} (for [[idx drop-area] (d/enumerate drop-areas)] @@ -184,7 +194,9 @@ (first selected-shapes)) parent (or selected-frame (get objects hover-top-frame-id)) - parent-bounds (:points parent)] + parent-bounds (:points parent) + + bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points]))] (when (and (some? parent) (not= uuid/zero (:id parent))) (let [children (->> (cph/get-immediate-children objects (:id parent)) @@ -200,7 +212,7 @@ (let [child-bounds (:points child) points (if (or (ctl/fill-height? child) (ctl/fill-height? child)) - (gsl/child-layout-bound-points parent child parent-bounds child-bounds) + (gsl/child-layout-bound-points parent child parent-bounds child-bounds bounds objects) child-bounds)] (for [point points] [:circle {:cx (:x point) @@ -222,7 +234,9 @@ (first selected-shapes)) parent (or selected-frame (get objects hover-top-frame-id)) - parent-bounds (:points parent)] + parent-bounds (:points parent) + + bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points]))] (when (and (some? parent) (not= uuid/zero (:id parent))) (let [children (->> (cph/get-immediate-children objects (:id parent)) @@ -237,7 +251,7 @@ origin (gpo/origin parent-bounds) {:keys [row-tracks column-tracks]} - (gsg/calc-layout-data parent children parent-bounds)] + (gsg/calc-layout-data parent parent-bounds children bounds objects)] [:* (for [row-data row-tracks] diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 70c935b82e..7f96444daa 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -762,10 +762,12 @@ height (gpo/height-points bounds) origin (gpo/origin bounds) + all-bounds (d/lazy-map (keys objects) #(gsh/shape->points (get objects %))) + {:keys [row-tracks column-tracks] :as layout-data} (mf/use-memo (mf/deps shape children) - #(gsg/calc-layout-data shape children bounds)) + #(gsg/calc-layout-data shape bounds children all-bounds objects)) handle-pointer-down (mf/use-callback From 3db04e1e2be456aecd205dc8b1c3b9fc40d7acb7 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 5 Oct 2023 16:44:03 +0200 Subject: [PATCH 5/8] :bug: Fix problem when removing margins --- common/src/app/common/data.cljc | 14 ++++++++++++++ .../src/app/main/data/workspace/shape_layout.cljs | 2 +- .../sidebar/options/menus/layout_item.cljs | 7 ++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index 0fcdc88f32..a0646bdf79 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -223,6 +223,20 @@ ([data] (into {} (without-nils) data))) +(defn without-nils-deep + "Given a map remove the `nil` values and when a child map is found + recursively removes them as well." + [data] + (let [data (without-nils + (c/update-vals + data + (fn [value] + (cond-> value + (map? value) + (without-nils-deep)))))] + (when (not-empty? data) + data))) + (defn without-qualified ([] (remove (comp qualified-keyword? key))) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 45dd0d30c9..d09f257a1f 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -553,7 +553,7 @@ parent-ids (->> ids (map #(cph/get-parent-id objects %))) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids #(d/deep-merge (or % {}) changes)) + (dwc/update-shapes ids #(d/without-nils-deep (d/deep-merge (or % {}) changes))) (dwc/update-shapes children-ids (partial fix-child-sizing objects changes)) (dwc/update-shapes parent-ids (fn [parent] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index 1b2a2fc4ed..21e9508c06 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -45,21 +45,18 @@ m1 (when (and (not (= :multiple (:layout-item-margin values))) (= (dm/get-in values [:layout-item-margin :m1]) (dm/get-in values [:layout-item-margin :m3]))) - (dm/get-in values [:layout-item-margin :m1]) - ) + (dm/get-in values [:layout-item-margin :m1])) m2 (when (and (not (= :multiple (:layout-item-margin values))) (= (dm/get-in values [:layout-item-margin :m2]) (dm/get-in values [:layout-item-margin :m4]))) - (dm/get-in values [:layout-item-margin :m2]) - ) + (dm/get-in values [:layout-item-margin :m2])) select-margins (fn [m1? m2? m3? m4?] (st/emit! (udw/set-margins-selected {:m1 m1? :m2 m2? :m3 m3? :m4 m4?}))) select-margin #(select-margins (= % :m1) (= % :m2) (= % :m3) (= % :m4))] - (mf/use-effect (fn [] (fn [] From caee3160f21253b974e2280882f31bb4deda0a19 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 6 Oct 2023 12:17:25 +0200 Subject: [PATCH 6/8] :bug: Change to patch-object --- common/src/app/common/data.cljc | 44 +++++++++++++------ .../app/main/data/workspace/shape_layout.cljs | 29 ++++++------ .../options/menus/layout_container.cljs | 13 ++++++ 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/common/src/app/common/data.cljc b/common/src/app/common/data.cljc index a0646bdf79..1d7b4959ee 100644 --- a/common/src/app/common/data.cljc +++ b/common/src/app/common/data.cljc @@ -223,20 +223,6 @@ ([data] (into {} (without-nils) data))) -(defn without-nils-deep - "Given a map remove the `nil` values and when a child map is found - recursively removes them as well." - [data] - (let [data (without-nils - (c/update-vals - data - (fn [value] - (cond-> value - (map? value) - (without-nils-deep)))))] - (when (not-empty? data) - data))) - (defn without-qualified ([] (remove (comp qualified-keyword? key))) @@ -251,6 +237,36 @@ (persistent! (reduce dissoc! (transient data) keys)) (reduce dissoc data keys))) +(defn patch-object + "Changes is some attributes that need to change in object. + When the attribute is nil it will be removed. + + For example + - object: {:a 1 :b {:foo 1 :bar 2} :c 10} + - changes: {:a 2 :b {:foo nil :k 3}} + - result: {:a 2 :b {:bar 2 :k 3} :c 10} + " + ([changes] + #(patch-object % changes)) + + ([object changes] + (->> changes + (reduce-kv + (fn [object key value] + (cond + (map? value) + (update object key patch-object value) + + (and (nil? value) (record? object)) + (assoc object key nil) + + (nil? value) + (dissoc object key value) + + :else + (assoc object key value))) + object)))) + (defn remove-at-index "Takes a vector and returns a vector with an element in the specified index removed." diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index d09f257a1f..e69d6c9146 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -369,7 +369,7 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids #(d/deep-merge % changes)) + (dwc/update-shapes ids (d/patch-object changes)) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -553,14 +553,15 @@ parent-ids (->> ids (map #(cph/get-parent-id objects %))) undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (dwc/update-shapes ids #(d/without-nils-deep (d/deep-merge (or % {}) changes))) + (dwc/update-shapes ids (d/patch-object changes)) (dwc/update-shapes children-ids (partial fix-child-sizing objects changes)) - (dwc/update-shapes parent-ids - (fn [parent] - (-> parent - (fix-parent-sizing objects (set ids) changes) - (cond-> (ctl/grid-layout? parent) - (ctl/assign-cells))))) + (dwc/update-shapes + parent-ids + (fn [parent] + (-> parent + (fix-parent-sizing objects (set ids) changes) + (cond-> (ctl/grid-layout? parent) + (ctl/assign-cells))))) (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) @@ -577,11 +578,13 @@ [layout-id] (fn [shape] (->> ids - (reduce (fn [shape cell-id] - (-> shape - (d/update-in-when [:layout-grid-cells cell-id] - #(d/without-nils (merge % props))))) - shape)))) + (reduce + (fn [shape cell-id] + (d/update-in-when + shape + [:layout-grid-cells cell-id] + d/patch-object props)) + shape)))) (ptk/data-event :layout/update [layout-id]) (dwu/commit-undo-transaction undo-id)))))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index dd62d15a55..8820a30bf0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -525,6 +525,7 @@ :on-focus #(do (dom/select-target %) (select-paddings true false true false)) + :nillable true :min 0 :value p1}]] [:div {:class (stl/css :padding-simple) @@ -539,6 +540,7 @@ :on-focus #(do (dom/select-target %) (select-paddings false true false true)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value p2}]]] (= padding-type :multiple) @@ -555,6 +557,7 @@ :on-focus #(do (dom/select-target %) (select-padding :p1)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value (:p1 (:layout-padding values))}]] @@ -569,6 +572,7 @@ :on-focus #(do (dom/select-target %) (select-padding :p2)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value (:p2 (:layout-padding values))}]] @@ -583,6 +587,7 @@ :on-focus #(do (dom/select-target %) (select-padding :p3)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value (:p3 (:layout-padding values))}]] @@ -597,6 +602,7 @@ :on-focus #(do (dom/select-target %) (select-padding :p4)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value (:p4 (:layout-padding values))}]]])] [:button {:class (stl/css-case :padding-toggle true @@ -618,6 +624,7 @@ :on-focus #(do (dom/select-target %) (select-paddings true false true false)) + :nillable true :min 0 :value p1}]] @@ -630,6 +637,7 @@ :on-focus #(do (dom/select-target %) (select-paddings false true false true)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value p2}]]] @@ -650,6 +658,7 @@ :on-focus #(do (dom/select-target %) (select-padding num)) :on-blur #(select-paddings false false false false) + :nillable true :min 0 :value (num (:layout-padding values))}]]])]) @@ -691,6 +700,7 @@ :on-blur (fn [_] (select-gap nil) (reset! gap-selected? :none)) + :nillable true :min 0 :value (:row-gap gap-value) :disabled (and (= :nowrap wrap-type) (not is-col?))}]] @@ -710,6 +720,7 @@ :on-blur (fn [_] (select-gap nil) (reset! gap-selected? :none)) + :nillable true :min 0 :value (:column-gap gap-value) :disabled (and (= :nowrap wrap-type) is-col?)}]]] @@ -731,6 +742,7 @@ :on-blur (fn [_] (select-gap nil) (reset! gap-selected? :none)) + :nillable true :min 0 :value (:column-gap gap-value) :disabled (and (= :nowrap wrap-type) is-col?)}]] @@ -749,6 +761,7 @@ :on-blur (fn [_] (select-gap nil) (reset! gap-selected? :none)) + :nillable true :min 0 :value (:row-gap gap-value) :disabled (and (= :nowrap wrap-type) (not is-col?))}]]]]))) From 0468b6acca3cd4ddfe8194dd57434bd6ac998971 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 6 Oct 2023 12:18:06 +0200 Subject: [PATCH 7/8] :bug: Improve immediate-children helper --- .../src/app/common/geom/shapes/min_size_layout.cljc | 10 ++++------ common/src/app/common/pages/helpers.cljc | 13 ++++++++++--- .../src/app/main/ui/workspace/viewport/debug.cljs | 4 +++- .../ui/workspace/viewport/grid_layout_editor.cljs | 8 ++++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/common/src/app/common/geom/shapes/min_size_layout.cljc b/common/src/app/common/geom/shapes/min_size_layout.cljc index 7bd3b088a2..9b2d5bcdfe 100644 --- a/common/src/app/common/geom/shapes/min_size_layout.cljc +++ b/common/src/app/common/geom/shapes/min_size_layout.cljc @@ -7,7 +7,6 @@ (ns app.common.geom.shapes.min-size-layout (:require [app.common.data :as d] - [app.common.geom.shapes.common :as gco] [app.common.geom.shapes.flex-layout.bounds :as fb] [app.common.geom.shapes.flex-layout.layout-data :as fd] [app.common.geom.shapes.grid-layout.bounds :as gb] @@ -22,15 +21,14 @@ (cond (and (ctl/fill-width? child) (ctl/flex-layout? child)) - (gpo/width-points (fb/layout-content-bounds bounds child (->> child :shapes (map (d/getf objects))) objects)) + (let [children (->> child :shapes (map (d/getf objects)))] + (gpo/width-points (fb/layout-content-bounds bounds child children objects))) (and (ctl/fill-width? child) (ctl/grid-layout? child)) (let [children - (->> (cph/get-immediate-children objects (:id child)) - (remove :hidden) - (remove gco/invalid-geometry?) - (map (fn [child] [@(get bounds (:id child)) child]))) + (->> (cph/get-immediate-children objects (:id child) {:remove-hidden true}) + (map #(vector @(get bounds (:id %)) %))) layout-data (gd/calc-layout-data child @(get bounds (:id child)) children bounds objects true)] (gpo/width-points (gb/layout-content-bounds bounds child layout-data))) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index c0885d892f..4d79957b05 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.geom.shapes.common :as gco] [app.common.types.components-list :as ctkl] [app.common.types.pages-list :as ctpl] [app.common.types.shape.layout :as ctl] @@ -266,12 +267,18 @@ (defn get-immediate-children "Retrieve resolved shape objects that are immediate children of the specified shape-id" - ([objects] (get-immediate-children objects uuid/zero)) - ([objects shape-id] + ([objects] (get-immediate-children objects uuid/zero nil)) + ([objects shape-id] (get-immediate-children objects shape-id nil)) + ([objects shape-id {:keys [remove-hidden remove-blocked] :or {remove-hidden false remove-blocked false}}] (let [lookup (d/getf objects)] (->> (lookup shape-id) (:shapes) - (keep lookup))))) + (keep (fn [cid] + (when-let [child (lookup cid)] + (when (and (or (not remove-hidden) (not (:hidden child))) + (or (not remove-blocked) (not (:blocked child)))) + child)))) + (remove gco/invalid-geometry?))))) (declare indexed-shapes) diff --git a/frontend/src/app/main/ui/workspace/viewport/debug.cljs b/frontend/src/app/main/ui/workspace/viewport/debug.cljs index 0e870a2751..8079d61210 100644 --- a/frontend/src/app/main/ui/workspace/viewport/debug.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/debug.cljs @@ -41,9 +41,11 @@ (remove :hidden)) bounds (d/lazy-map (keys objects) #(dm/get-in objects [% :points])) + children+bounds (->> children (map (fn [shape] [@(get bounds (:id shape)) shape]))) + grid-layout-data (when (ctl/grid-layout? shape) - (gsg/calc-layout-data shape (:points shape) children bounds objects)) + (gsg/calc-layout-data shape (:points shape) children+bounds bounds objects)) layout-bounds (cond (ctl/flex-layout? shape) diff --git a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs index 7f96444daa..8d7f64886c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/grid_layout_editor.cljs @@ -748,10 +748,10 @@ objects (-> objects (gsh/apply-objects-modifiers (select-keys modifiers ids)) (gsh/update-shapes-geometry (reverse ids)))] - (->> (:shapes shape) - (map (d/getf objects)) - (remove :hidden) - (map #(vector (gpo/parent-coords-bounds (:points %) (:points shape)) %)))))) + (->> (cph/get-immediate-children objects (:id shape)) + (keep (fn [child] + (when-not (:hidden child) + [(gpo/parent-coords-bounds (:points child) (:points shape)) child]))))))) children (hooks/use-equal-memo children) From 59bd9c132ef0fe9df6278eff4bb66a5725d20b8f Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 6 Oct 2023 14:05:22 +0200 Subject: [PATCH 8/8] :bug: Fix fill inside grid layout --- .../geom/shapes/flex_layout/bounds.cljc | 76 ++++++++++++------- .../src/app/common/geom/shapes/modifiers.cljc | 8 +- .../app/main/data/workspace/transforms.cljs | 1 - .../app/util/code_gen/style_css_values.cljs | 8 +- 4 files changed, 57 insertions(+), 36 deletions(-) diff --git a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc index a8a268436d..540b886860 100644 --- a/common/src/app/common/geom/shapes/flex_layout/bounds.cljc +++ b/common/src/app/common/geom/shapes/flex_layout/bounds.cljc @@ -27,7 +27,7 @@ (defn child-layout-bound-points "Returns the bounds of the children as points" - [parent child parent-bounds child-bounds bounds objects] + [parent child parent-bounds child-bounds correct-v bounds objects] (let [row? (ctl/row? parent) col? (ctl/col? parent) @@ -68,37 +68,50 @@ ;; We need some height/width to calculate the bounds. We stablish the minimum min-width (max min-width 0.01) - min-height (max min-height 0.01)] + min-height (max min-height 0.01) - (cond-> [base-p - (gpt/add base-p (hv 0.01)) - (gpt/add base-p (vv 0.01))] + base-p (gpt/add base-p correct-v) - col? - (conj (gpt/add base-p (vv min-height))) + result + (cond-> [base-p + (gpt/add base-p (hv 0.01)) + (gpt/add base-p (vv 0.01))] - row? - (conj (gpt/add base-p (hv min-width))) + col? + (conj (gpt/add base-p (vv min-height))) - (and col? h-start?) - (conj (gpt/add base-p (hv min-width))) + row? + (conj (gpt/add base-p (hv min-width))) - (and col? h-center?) - (conj (gpt/add base-p (hv (/ min-width 2))) - (gpt/subtract base-p (hv (/ min-width 2)))) + (and col? h-start?) + (conj (gpt/add base-p (hv min-width))) - (and col? h-end?) - (conj (gpt/subtract base-p (hv min-width))) + (and col? h-center?) + (conj (gpt/add base-p (hv (/ min-width 2))) + (gpt/subtract base-p (hv (/ min-width 2)))) - (and row? v-start?) - (conj (gpt/add base-p (vv min-height))) + (and col? h-end?) + (conj (gpt/subtract base-p (hv min-width))) - (and row? v-center?) - (conj (gpt/add base-p (vv (/ min-height 2))) - (gpt/subtract base-p (vv (/ min-height 2)))) + (and row? v-start?) + (conj (gpt/add base-p (vv min-height))) - (and row? v-end?) - (conj (gpt/subtract base-p (vv min-height)))))) + (and row? v-center?) + (conj (gpt/add base-p (vv (/ min-height 2))) + (gpt/subtract base-p (vv (/ min-height 2)))) + + (and row? v-end?) + (conj (gpt/subtract base-p (vv min-height)))) + + correct-v + (cond-> correct-v + (and row? (ctl/fill-width? child)) + (gpt/subtract (hv (+ width min-width))) + + (and col? (ctl/fill-height? child)) + (gpt/subtract (vv (+ height min-height))) + )] + [result correct-v])) (defn layout-content-points [bounds parent children objects] @@ -106,26 +119,31 @@ (let [parent-id (:id parent) parent-bounds @(get bounds parent-id) get-child-bounds - (fn [child] + (fn [[result correct-v] child] (let [child-id (:id child) child-bounds @(get bounds child-id) [margin-top margin-right margin-bottom margin-left] (ctl/child-margins child) - child-bounds + [child-bounds correct-v] (if (or (ctl/fill-width? child) (ctl/fill-height? child)) - (child-layout-bound-points parent child parent-bounds child-bounds bounds objects) - child-bounds) + (child-layout-bound-points parent child parent-bounds child-bounds correct-v bounds objects) + [(->> child-bounds (map #(gpt/add % correct-v))) correct-v]) child-bounds (when (d/not-empty? child-bounds) (-> (gpo/parent-coords-bounds child-bounds parent-bounds) (gpo/pad-points (- margin-top) (- margin-right) (- margin-bottom) (- margin-left))))] - child-bounds))] + [(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?) - (map get-child-bounds)))) + (reduce get-child-bounds [[] (gpt/point 0)]) + (first)))) (defn layout-content-bounds [bounds {:keys [layout-padding] :as parent} children objects] diff --git a/common/src/app/common/geom/shapes/modifiers.cljc b/common/src/app/common/geom/shapes/modifiers.cljc index c082e9ab9d..ebb1db8e07 100644 --- a/common/src/app/common/geom/shapes/modifiers.cljc +++ b/common/src/app/common/geom/shapes/modifiers.cljc @@ -307,6 +307,8 @@ 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)) @@ -333,7 +335,8 @@ (set-grid-layout-modifiers objects bounds parent transformed-parent-bounds)) ;; Auto-width/height can change the positions in the parent so we need to recalculate - (cond-> autolayouts auto? (conj (:id parent)))])) + ;; also if the child is fill width/height inside a grid layout + (cond-> autolayouts (or auto? fill-with-grid?) (conj (:id parent)))])) (defn- apply-structure-modifiers [objects modif-tree] @@ -415,7 +418,8 @@ (contains? to-reflow current) (disj current))] - (if (ctm/empty? auto-resize-modifiers) + (if (and (ctm/empty? auto-resize-modifiers) + (not (ctl/grid-layout? objects (:parent-id parent-base)))) (recur modif-tree bounds (rest sizing-auto-layouts) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index ce1cd5a1dd..48403d3626 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -712,7 +712,6 @@ (defn update-position "Move shapes to a new position" [id position] - (js/console.log "DEBUG" (pr-str position)) (dm/assert! (uuid? id)) (ptk/reify ::update-position diff --git a/frontend/src/app/util/code_gen/style_css_values.cljs b/frontend/src/app/util/code_gen/style_css_values.cljs index dae838040e..175d185e17 100644 --- a/frontend/src/app/util/code_gen/style_css_values.cljs +++ b/frontend/src/app/util/code_gen/style_css_values.cljs @@ -75,9 +75,9 @@ [_ shape objects] (let [parent (cph/get-parent objects (:id shape))] (when (and (ctl/flex-layout-immediate-child? objects shape) - (or (and (contains? #{:row :reverse-row} (:layout-flex-dir parent)) + (or (and (contains? #{:row :row-reverse} (:layout-flex-dir parent)) (= :fill (:layout-item-h-sizing shape))) - (and (contains? #{:column :column-row} (:layout-flex-dir parent)) + (and (contains? #{:column :column-reverse} (:layout-flex-dir parent)) (= :fill (:layout-item-v-sizing shape))))) 1))) @@ -90,10 +90,10 @@ (cond (and (ctl/flex-layout-immediate-child? objects shape) (or (and (= type :height) - (contains? #{:row :reverse-row} (:layout-flex-dir parent)) + (contains? #{:row :row-reverse} (:layout-flex-dir parent)) (= :fill (:layout-item-v-sizing shape))) (and (= type :width) - (contains? #{:column :column-row} (:layout-flex-dir parent)) + (contains? #{:column :column-reverse} (:layout-flex-dir parent)) (= :fill (:layout-item-h-sizing shape))))) :fill