From 79a46efa35d1d5332f3d6e74e70f87ba2e1be9a6 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 6 Jun 2022 21:45:14 +0200 Subject: [PATCH] :sparkles: Create nested frames from selection --- common/src/app/common/pages/helpers.cljc | 33 +++++++++--------- frontend/src/app/main/data/workspace.cljs | 14 ++++---- .../src/app/main/data/workspace/common.cljs | 5 ++- .../main/ui/workspace/viewport/actions.cljs | 34 +++++++++---------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index b132ccc1eb..d7a86f7a48 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -227,17 +227,19 @@ (defn is-shape-over-shape? [objects base-shape-id over-shape-id] - (let [[base parent-a parent-b] (get-base objects base-shape-id over-shape-id)] + (let [[base index-a index-b] (get-base objects base-shape-id over-shape-id)] (cond (= base base-shape-id) - ;; over-shape is a child of base-shape. Will be over if base is a root-frame - (= uuid/zero (get-in objects [base-shape-id :parent-id])) + + (and (frame-shape? objects over-shape-id) + (root-frame? objects over-shape-id)) (= base over-shape-id) - (not= uuid/zero (get-in objects [over-shape-id :parent-id])) + (or (not (frame-shape? objects over-shape-id)) + (not (root-frame? objects over-shape-id))) :else - (< parent-a parent-b)))) + (> index-a index-b)))) (defn sort-z-index ([objects ids] @@ -266,17 +268,11 @@ (defn frame-id-by-position [objects position] - (let [frames (->> (get-frames objects) - (filter #(and position (gsh/has-point? % position)))) - - top-frame - (reduce (fn [current-top frame] - (if (is-shape-over-shape? objects (:id current-top) (:id frame)) - frame - current-top)) - (first frames) - (rest frames))] - (or (:id top-frame) uuid/zero))) + (let [top-frame + (->> (get-frames-ids objects) + (sort-z-index objects) + (d/seek #(and position (gsh/has-point? (get objects %) position))))] + (or top-frame uuid/zero))) (defn frame-by-position [objects position] @@ -630,3 +626,8 @@ (-> (select-keys objects selected+parents) (d/update-vals remove-children)))) + +(defn is-child? + [objects parent-id candidate-child-id] + (let [parents (get-parents-seq objects candidate-child-id)] + (some? (d/seek #(= % parent-id) parents)))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 9f8f9deb5f..e05a4f9074 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1673,20 +1673,22 @@ (watch [_ state _] (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - shapes (cph/get-immediate-children objects) selected (wsh/lookup-selected state) - selected-objs (map #(get objects %) selected) - has-frame? (some #(= (:type %) :frame) selected-objs)] - (when (not (or (empty? selected) has-frame?)) + selected-objs (map #(get objects %) selected)] + (when (d/not-empty? selected) (let [srect (gsh/selection-rect selected-objs) - frame-id (:frame-id (first shapes)) + frame-id (get-in objects [(first selected) :frame-id]) + parent-id (get-in objects [(first selected) :parent-id]) shape (-> (cp/make-minimal-shape :frame) (merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)}) - (assoc :frame-id frame-id) + (assoc :frame-id frame-id :parent-id parent-id) + (cond-> (not= frame-id uuid/zero) + (assoc :fills [] :hide-in-viewer true)) (cp/setup-rect-selrect))] (rx/of (dwu/start-undo-transaction) (dwc/add-shape shape) + (dwc/move-shapes-into-frame (:id shape) selected) (dwu/commit-undo-transaction)))))))) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index e5296d2101..0e5ff1fe96 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -313,7 +313,10 @@ selected) changes (-> (pcb/empty-changes it page-id) - (pcb/add-object shape #_{:index (when (= :frame (:type shape)) 0)}))] + (pcb/with-objects objects) + (pcb/add-object shape) + (cond-> (some? (:parent-id attrs)) + (pcb/change-parent (:parent-id attrs) [shape])))] (rx/concat (rx/of (dch/commit-changes changes) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index b02b804897..c7e8b1eb40 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -8,6 +8,7 @@ (:require [app.common.geom.point :as gpt] [app.common.math :as mth] + [app.common.pages.helpers :as cph] [app.common.uuid :as uuid] [app.config :as cfg] [app.main.data.workspace :as dw] @@ -165,6 +166,7 @@ (defn on-double-click [hover hover-ids drawing-path? objects edition] + (mf/use-callback (mf/deps @hover @hover-ids drawing-path? edition) (fn [event] @@ -174,30 +176,28 @@ alt? (kbd/alt? event) meta? (kbd/meta? event) - {:keys [id type] :as shape} @hover + {:keys [id type] :as shape} (or @hover (get objects (first @hover-ids))) - frame? (= :frame type) - group? (= :group type)] + editable? (contains? #{:text :rect :path :image :circle} type)] (st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt? meta?)) ;; Emit asynchronously so the double click to exit shapes won't break (timers/schedule - #(when (and (not drawing-path?) shape) - (cond - frame? - (st/emit! (dw/select-shape id shift?)) + (fn [] + (when (and (not drawing-path?) shape) + (cond + (and editable? (not= id edition)) + (st/emit! (dw/select-shape id) + (dw/start-editing-selected)) - (and group? (> (count @hover-ids) 1)) - (let [selected (get objects (second @hover-ids))] - (reset! hover selected) - (reset! hover-ids (into [] (rest @hover-ids))) - - (st/emit! (dw/select-shape (:id selected)))) - - (not= id edition) - (st/emit! (dw/select-shape id) - (dw/start-editing-selected))))))))) + :else + (let [;; We only get inside childrens of the hovering shape + hover-ids (->> @hover-ids (filter (partial cph/is-child? objects id))) + selected (get objects (if (> (count hover-ids) 1) (second hover-ids) (first hover-ids)))] + (when (some? selected) + (reset! hover selected) + (st/emit! (dw/select-shape (:id selected))))))))))))) (defn on-context-menu [hover hover-ids]