From 9b8ef356037cb3ff39c51fa791d50327d6afcda1 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 5 Jun 2023 18:07:41 +0200 Subject: [PATCH] :sparkles: Grid layers order --- .../src/app/common/pages/changes_builder.cljc | 40 +++++++++++ common/src/app/common/types/shape/layout.cljc | 70 +++++++++++++++++-- frontend/src/app/main/data/workspace.cljs | 6 ++ .../src/app/main/data/workspace/changes.cljs | 1 + .../app/main/data/workspace/selection.cljs | 3 +- .../app/main/data/workspace/shape_layout.cljs | 46 +----------- .../src/app/main/data/workspace/shapes.cljs | 7 +- .../app/main/data/workspace/transforms.cljs | 6 +- 8 files changed, 125 insertions(+), 54 deletions(-) diff --git a/common/src/app/common/pages/changes_builder.cljc b/common/src/app/common/pages/changes_builder.cljc index be93f9cc7..08c2db3d8 100644 --- a/common/src/app/common/pages/changes_builder.cljc +++ b/common/src/app/common/pages/changes_builder.cljc @@ -17,6 +17,7 @@ [app.common.pages.helpers :as cph] [app.common.types.component :as ctk] [app.common.types.file :as ctf] + [app.common.types.shape.layout :as ctl] [app.common.uuid :as uuid])) ;; Auxiliary functions to help create a set of changes (undo + redo) @@ -712,3 +713,42 @@ (-> changes (update :redo-changes add-ignore-remote) (update :undo-changes add-ignore-remote)))) + +(defn reorder-grid-children + [changes ids] + (assert-page-id changes) + (assert-objects changes) + + (let [page-id (::page-id (meta changes)) + objects (lookup-objects changes) + + reorder-grid + (fn [changes grid] + (let [old-shapes (:shapes grid) + grid (ctl/reorder-grid-children grid) + + redo-change + {:type :mov-objects + :parent-id (:id grid) + :page-id page-id + :shapes (:shapes grid) + :index 0} + + undo-change + {:type :mov-objects + :parent-id (:id grid) + :page-id page-id + :shapes old-shapes + :index 0}] + (-> changes + (update :redo-changes conj redo-change) + (update :undo-changes d/preconj undo-change) + (apply-changes-local)))) + + changes + (->> ids + (map (d/getf objects)) + (filter ctl/grid-layout?) + (reduce reorder-grid changes))] + + changes)) diff --git a/common/src/app/common/types/shape/layout.cljc b/common/src/app/common/types/shape/layout.cljc index 1de4aed70..bb4017a43 100644 --- a/common/src/app/common/types/shape/layout.cljc +++ b/common/src/app/common/types/shape/layout.cljc @@ -595,7 +595,7 @@ layout-grid-cells (->> (d/enumerate rows) - (reduce (fn [result [row-idx _row]] + (reduce (fn [result [row-idx _]] (let [id (uuid/next)] (assoc result id (merge {:id id @@ -618,7 +618,7 @@ layout-grid-cells (->> (d/enumerate cols) - (reduce (fn [result [col-idx _col]] + (reduce (fn [result [col-idx _]] (let [id (uuid/next)] (assoc result id (merge {:id id @@ -699,16 +699,20 @@ ([parent] (get-cells parent nil)) - ([{:keys [layout-grid-cells layout-grid-dir]} {:keys [sort?] :or {sort? false}}] + ([{: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)] + (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 get-free-cells @@ -739,7 +743,35 @@ (assoc parent :layout-grid-cells cells))) -;; TODO +(defn overlapping-cells + "Find overlapping cells" + [parent] + (let [cells (->> parent + :layout-grid-cells + (map (fn [[id cell]] + [id (sga/make-area cell)]))) + find-overlaps + (fn [result [id area]] + (let [[fid _] + (d/seek #(and (not= (first %) id) + (sga/intersects? (second %) area)) + cells)] + (cond-> result + (some? fid) + (conj #{id fid}))))] + (reduce find-overlaps #{} cells))) + +;; FIXME: This is only for development +#_(defn fix-overlaps + [parent overlaps] + (reduce (fn [parent ids] + (let [id (if (empty? (get-in parent [:layout-grid-cells (first ids)])) + (first ids) + (second ids))] + (update parent :layout-grid-cells dissoc id))) + parent + overlaps)) + ;; 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 @@ -798,6 +830,8 @@ cells (update-in cells [next-free :shapes] conj current)] (recur cells (rest free-cells) (rest pending)))))] + ;; TODO: Remove after testing + (assert (empty? (overlapping-cells parent)) (dm/str (overlapping-cells parent))) (assoc parent :layout-grid-cells cells))))) (defn free-cell-push @@ -1009,3 +1043,29 @@ (cond-> (some? cell) (push-into-cell children row column)) (assign-cells)))) + +(defn add-children-to-index + [parent ids objects to-index] + (let [ids (into (d/ordered-set) ids) + cells (get-cells parent {:sort? true :remove-empty? true}) + to-index (- (count cells) to-index) + target-cell (nth cells to-index nil)] + + (cond-> parent + (some? target-cell) + (add-children-to-cell ids objects [(:row target-cell) (:column target-cell)])))) + +(defn reorder-grid-children + [parent] + (let [cells (get-cells parent {:sort? true}) + child? (set (:shapes parent)) + new-shapes + (into (d/ordered-set) + (comp (keep (comp first :shapes)) + (filter child?)) + cells) + + ;; Add the children that are not in cells (absolute positioned for example) + new-shapes (into new-shapes (:shapes parent))] + + (assoc parent :shapes (into [] (reverse new-shapes))))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index acb2bfdd1..f74ae2c76 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -785,11 +785,17 @@ parent))) ;; Update grid layout + (cond-> (ctl/grid-layout? objects parent-id) + (pcb/update-shapes [parent-id] #(ctl/add-children-to-index % ids objects to-index))) + (pcb/update-shapes parents (fn [parent] (cond-> parent (ctl/grid-layout? parent) (ctl/assign-cells)))) + + (pcb/reorder-grid-children parents) + ;; Resize parent containers that need to (pcb/resize-parents parents)))) diff --git a/frontend/src/app/main/data/workspace/changes.cljs b/frontend/src/app/main/data/workspace/changes.cljs index a8461f415..2868ce4a8 100644 --- a/frontend/src/app/main/data/workspace/changes.cljs +++ b/frontend/src/app/main/data/workspace/changes.cljs @@ -80,6 +80,7 @@ (pcb/set-stack-undo? stack-undo?) (pcb/with-objects objects)) ids) + changes (pcb/reorder-grid-children changes ids) changes (add-undo-group changes state)] (rx/concat (if (seq (:redo-changes changes)) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index ec88cd88c..3219d56be 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -450,7 +450,8 @@ changes (-> (pcb/add-object changes new-obj) (pcb/amend-last-change #(assoc % :old-id (:id obj))) (cond-> (ctl/grid-layout? objects (:parent-id obj)) - (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells))) + (-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells) + (pcb/reorder-grid-children [(:parent-id obj)])))) changes (cond-> changes (and is-component-root? is-component-main?) diff --git a/frontend/src/app/main/data/workspace/shape_layout.cljs b/frontend/src/app/main/data/workspace/shape_layout.cljs index 2642bb3b7..bba3d9bda 100644 --- a/frontend/src/app/main/data/workspace/shape_layout.cljs +++ b/frontend/src/app/main/data/workspace/shape_layout.cljs @@ -196,7 +196,9 @@ (assoc :layout-item-h-sizing :auto :layout-item-v-sizing :auto)) (merge layout-params) - (cond-> (= type :grid) (ctl/assign-cells))))) + (cond-> (= type :grid) + (-> (ctl/assign-cells) + (ctl/reorder-grid-children)))))) (ptk/data-event :layout/update ids) (dwc/update-shapes children-ids #(dissoc % :constraints-h :constraints-v)) (dwu/commit-undo-transaction undo-id)))))) @@ -370,48 +372,6 @@ (ptk/data-event :layout/update ids) (dwu/commit-undo-transaction undo-id)))))) -#_(defn update-grid-cells - [parent objects] - (let [children (cph/get-immediate-children objects (:id parent)) - layout-grid-rows (:layout-grid-rows parent) - layout-grid-columns (:layout-grid-columns parent) - num-rows (count layout-grid-columns) - num-columns (count layout-grid-columns) - layout-grid-cells (:layout-grid-cells parent) - - allocated-shapes - (into #{} (mapcat :shapes) (:layout-grid-cells parent)) - - no-cell-shapes - (->> children (:shapes parent) (remove allocated-shapes)) - - layout-grid-cells - (for [[row-idx row] (d/enumerate layout-grid-rows) - [col-idx col] (d/enumerate layout-grid-columns)] - - (let [shape (nth children (+ (* row-idx num-columns) col-idx) nil) - cell-data {:id (uuid/next) - :row (inc row-idx) - :column (inc col-idx) - :row-span 1 - :col-span 1 - :shapes (when shape [(:id shape)])}] - [(:id cell-data) cell-data]))] - (assoc parent :layout-grid-cells (into {} layout-grid-cells)))) - -#_(defn check-grid-cells-update - [ids] - (ptk/reify ::check-grid-cells-update - ptk/WatchEvent - (watch [_ state _] - (let [objects (wsh/lookup-page-objects state) - undo-id (js/Symbol)] - (rx/of (dwc/update-shapes - ids - (fn [shape] - (-> shape - (update-grid-cells objects))))))))) - (defn add-layout-track [ids type value] (assert (#{:row :column} type)) diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index d23ad2dc7..9b9833ac0 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -95,8 +95,8 @@ (cond-> (some? cell) (pcb/update-shapes [(:parent-id shape)] #(ctl/push-into-cell % [id] row column))) (cond-> (ctl/grid-layout? objects (:parent-id shape)) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)))] - + (-> (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells) + (pcb/reorder-grid-children [(:parent-id shape)]))))] [shape changes])) (defn add-shape @@ -144,7 +144,8 @@ (pcb/update-shapes ordered-indexes #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/change-parent frame-id to-move-shapes 0) (cond-> (ctl/grid-layout? objects frame-id) - (pcb/update-shapes [frame-id] ctl/assign-cells)))))) + (pcb/update-shapes [frame-id] ctl/assign-cells)) + (pcb/reorder-grid-children [frame-id]))))) (defn move-shapes-into-frame [frame-id shapes] diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 6cc4b3995..2e94d9516 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -539,8 +539,8 @@ (fn [[_ target-frame drop-index]] (let [undo-id (js/Symbol)] (rx/of (dwu/start-undo-transaction undo-id) - (move-shapes-to-frame ids target-frame drop-index) (dwm/apply-modifiers {:undo-transation? false}) + (move-shapes-to-frame ids target-frame drop-index) (finish-transform) (dwu/commit-undo-transaction undo-id)))))))))))))) @@ -608,7 +608,8 @@ (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] (assoc shape :layout-grid-cells layout-grid-cells))) + (pcb/reorder-grid-children [(:id parent)])))) changes (->> selected @@ -812,6 +813,7 @@ (pcb/update-shapes moving-shapes-ids #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true))) (pcb/update-shapes shape-ids-to-detach ctk/detach-shape) (pcb/change-parent frame-id moving-shapes drop-index) + (pcb/reorder-grid-children [frame-id]) (pcb/remove-objects empty-parents))] (when (and (some? frame-id) (d/not-empty? changes))