From bf66e12075d1f4d8fff9cdedb4ebd164cb4d5734 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Mon, 3 Jun 2024 16:20:14 +0200 Subject: [PATCH] :sparkles: Allow masks, booleans, and some path read only --- .../src/app/main/data/workspace/groups.cljs | 127 +++++++++--------- .../app/main/data/workspace/shortcuts.cljs | 4 +- .../app/main/ui/workspace/context_menu.cljs | 4 +- frontend/src/app/plugins/shape.cljs | 78 ++++++++--- 4 files changed, 128 insertions(+), 85 deletions(-) diff --git a/frontend/src/app/main/data/workspace/groups.cljs b/frontend/src/app/main/data/workspace/groups.cljs index 4aa9aecb0..b813995e3 100644 --- a/frontend/src/app/main/data/workspace/groups.cljs +++ b/frontend/src/app/main/data/workspace/groups.cljs @@ -265,69 +265,76 @@ (let [selected (wsh/lookup-selected state)] (rx/of (ungroup-shapes selected :change-selection? true)))))) -(def mask-group - (ptk/reify ::mask-group - ptk/WatchEvent - (watch [it state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (->> (wsh/lookup-selected state) - (cfh/clean-loops objects) - (remove #(ctn/has-any-copy-parent? objects (get objects %)))) - shapes (shapes-for-grouping objects selected) - first-shape (first shapes)] - (when-not (empty? shapes) - (let [;; If the selected shape is a group, we can use it. If not, - ;; create a new group and set it as masked. - [group changes] - (if (and (= (count shapes) 1) - (= (:type (first shapes)) :group)) - [first-shape (-> (pcb/empty-changes it page-id) - (pcb/with-objects objects))] - (prepare-create-group (pcb/empty-changes it) (uuid/next) objects page-id shapes "Mask" true)) +(defn mask-group + ([] + (mask-group nil)) + ([ids] + (ptk/reify ::mask-group + ptk/WatchEvent + (watch [it state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + selected (->> (d/nilv ids (wsh/lookup-selected state)) + (cfh/clean-loops objects) + (remove #(ctn/has-any-copy-parent? objects (get objects %)))) + shapes (shapes-for-grouping objects selected) + first-shape (first shapes)] + (when-not (empty? shapes) + (let [;; If the selected shape is a group, we can use it. If not, + ;; create a new group and set it as masked. + [group changes] + (if (and (= (count shapes) 1) + (= (:type (first shapes)) :group)) + [first-shape (-> (pcb/empty-changes it page-id) + (pcb/with-objects objects))] + (prepare-create-group (pcb/empty-changes it) (uuid/next) objects page-id shapes "Mask" true)) - changes (-> changes - (pcb/update-shapes (:shapes group) - (fn [shape] - (assoc shape - :constraints-h :scale - :constraints-v :scale))) - (pcb/update-shapes [(:id group)] - (fn [group] - (assoc group - :masked-group true - :selrect (:selrect first-shape) - :points (:points first-shape) - :transform (:transform first-shape) - :transform-inverse (:transform-inverse first-shape)))) - (pcb/resize-parents [(:id group)])) - undo-id (js/Symbol)] + changes (-> changes + (pcb/update-shapes (:shapes group) + (fn [shape] + (assoc shape + :constraints-h :scale + :constraints-v :scale))) + (pcb/update-shapes [(:id group)] + (fn [group] + (assoc group + :masked-group true + :selrect (:selrect first-shape) + :points (:points first-shape) + :transform (:transform first-shape) + :transform-inverse (:transform-inverse first-shape)))) + (pcb/resize-parents [(:id group)])) + undo-id (js/Symbol)] - (rx/of (dwu/start-undo-transaction undo-id) - (dch/commit-changes changes) - (dws/select-shapes (d/ordered-set (:id group))) - (ptk/data-event :layout/update {:ids [(:id group)]}) - (dwu/commit-undo-transaction undo-id)))))))) + (rx/of (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dws/select-shapes (d/ordered-set (:id group))) + (ptk/data-event :layout/update {:ids [(:id group)]}) + (dwu/commit-undo-transaction undo-id))))))))) -(def unmask-group - (ptk/reify ::unmask-group - ptk/WatchEvent - (watch [it state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) +(defn unmask-group + ([] + (unmask-group nil)) - masked-groups (->> (wsh/lookup-selected state) - (map #(get objects %)) - (filter #(or (= :bool (:type %)) (= :group (:type %))))) + ([ids] + (ptk/reify ::unmask-group + ptk/WatchEvent + (watch [it state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) - changes (reduce (fn [changes mask] - (-> changes - (pcb/update-shapes [(:id mask)] - (fn [shape] - (dissoc shape :masked-group))) - (pcb/resize-parents [(:id mask)]))) - (-> (pcb/empty-changes it page-id) - (pcb/with-objects objects)) - masked-groups)] + masked-groups (->> (d/nilv ids (wsh/lookup-selected state)) + (map #(get objects %)) + (filter #(or (= :bool (:type %)) (= :group (:type %))))) - (rx/of (dch/commit-changes changes)))))) + changes (reduce (fn [changes mask] + (-> changes + (pcb/update-shapes [(:id mask)] + (fn [shape] + (dissoc shape :masked-group))) + (pcb/resize-parents [(:id mask)]))) + (-> (pcb/empty-changes it page-id) + (pcb/with-objects objects)) + masked-groups)] + + (rx/of (dch/commit-changes changes))))))) diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index 9dc525560..2d808a9bd 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -129,12 +129,12 @@ :mask {:tooltip (ds/meta "M") :command (ds/c-mod "m") :subsections [:modify-layers] - :fn #(emit-when-no-readonly dw/mask-group)} + :fn #(emit-when-no-readonly (dw/mask-group))} :unmask {:tooltip (ds/meta-shift "M") :command (ds/c-mod "shift+m") :subsections [:modify-layers] - :fn #(emit-when-no-readonly dw/unmask-group)} + :fn #(emit-when-no-readonly (dw/unmask-group))} :create-component {:tooltip (ds/meta "K") :command (ds/c-mod "k") diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 7f899e947..4dd499d18 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -244,9 +244,9 @@ is-bool? (and single? has-bool?) do-create-group #(st/emit! dw/group-selected) - do-mask-group #(st/emit! dw/mask-group) do-remove-group #(st/emit! dw/ungroup-selected) - do-unmask-group #(st/emit! dw/unmask-group) + do-mask-group #(st/emit! (dw/mask-group)) + do-unmask-group #(st/emit! (dw/unmask-group)) do-create-artboard-from-selection #(st/emit! (dwsh/create-artboard-from-selection))] diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index c68c142ea..f2dd16c0b 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -18,6 +18,7 @@ [app.common.types.shape.radius :as ctsr] [app.common.uuid :as uuid] [app.main.data.workspace :as udw] + [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shapes :as dwsh] @@ -27,6 +28,7 @@ [app.plugins.grid :as grid] [app.plugins.utils :as utils :refer [locate-objects locate-shape proxy->shape array-to-js]] [app.util.object :as obj] + [app.util.path.format :as upf] [app.util.text-editor :as ted])) (declare shape-proxy) @@ -58,30 +60,68 @@ ;; Only for frames + groups + booleans (getChildren [_] - (apply array (->> (locate-shape $file $page $id) - :shapes - (map #(shape-proxy $file $page %))))) + (let [shape (locate-shape $file $page $id)] + (if (or (cfh/frame-shape? shape) (cfh/group-shape? shape) (cfh/svg-raw-shape? shape) (cfh/bool-shape? shape)) + (apply array (->> (locate-shape $file $page $id) + :shapes + (map #(shape-proxy $file $page %)))) + (utils/display-not-valid :getChildren (:type shape))))) (appendChild [_ child] - (let [child-id (obj/get child "$id")] - (st/emit! (udw/relocate-shapes #{child-id} $id 0)))) + (let [shape (locate-shape $file $page $id)] + (if (or (cfh/frame-shape? shape) (cfh/group-shape? shape) (cfh/svg-raw-shape? shape) (cfh/bool-shape? shape)) + (let [child-id (obj/get child "$id")] + (st/emit! (udw/relocate-shapes #{child-id} $id 0))) + (utils/display-not-valid :appendChild (:type shape))))) (insertChild [_ index child] - (let [child-id (obj/get child "$id")] - (st/emit! (udw/relocate-shapes #{child-id} $id index)))) + (let [shape (locate-shape $file $page $id)] + (if (or (cfh/frame-shape? shape) (cfh/group-shape? shape) (cfh/svg-raw-shape? shape) (cfh/bool-shape? shape)) + (let [child-id (obj/get child "$id")] + (st/emit! (udw/relocate-shapes #{child-id} $id index))) + (utils/display-not-valid :insertChild (:type shape))))) ;; Only for frames (addFlexLayout [_] - (st/emit! (dwsl/create-layout-from-id $id :flex :from-frame? true :calculate-params? false)) - (grid/grid-layout-proxy $file $page $id)) + (let [shape (locate-shape $file $page $id)] + (if (cfh/frame-shape? shape) + (do (st/emit! (dwsl/create-layout-from-id $id :flex :from-frame? true :calculate-params? false)) + (grid/grid-layout-proxy $file $page $id)) + (utils/display-not-valid :addFlexLayout (:type shape))))) (addGridLayout [_] - (st/emit! (dwsl/create-layout-from-id $id :grid :from-frame? true :calculate-params? false)) - (grid/grid-layout-proxy $file $page $id))) + (let [shape (locate-shape $file $page $id)] + (if (cfh/frame-shape? shape) + (do (st/emit! (dwsl/create-layout-from-id $id :grid :from-frame? true :calculate-params? false)) + (grid/grid-layout-proxy $file $page $id)) + (utils/display-not-valid :addGridLayout (:type shape))))) + + ;; Make masks for groups + (makeMask + [_] + (let [shape (locate-shape $file $page $id)] + (if (cfh/group-shape? shape) + (st/emit! (dwg/mask-group #{$id})) + (utils/display-not-valid :makeMask (:type shape))))) + + (removeMask + [_] + (let [shape (locate-shape $file $page $id)] + (if (cfh/mask-shape? shape) + (st/emit! (dwg/unmask-group #{$id})) + (utils/display-not-valid :removeMask (:type shape))))) + + ;; Only for path and bool shapes + (toD + [_] + (let [shape (locate-shape $file $page $id)] + (if (cfh/path-shape? shape) + (upf/format-path (:content shape)) + (utils/display-not-valid :makeMask (:type shape)))))) (crc/define-properties! ShapeProxy @@ -388,11 +428,6 @@ :enumerable false :get #(.getChildren ^js %)})) - (cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data))) - (-> (obj/unset! "appendChild") - (obj/unset! "insertChild") - (obj/unset! "getChildren"))) - (cond-> (cfh/frame-shape? data) (-> (crc/add-properties! {:name "grid" @@ -440,10 +475,6 @@ (when (contains? #{:fix :auto} value) (st/emit! (dwsl/update-layout #{id} {:layout-item-v-sizing value})))))}))) - (cond-> (not (cfh/frame-shape? data)) - (-> (obj/unset! "addGridLayout") - (obj/unset! "addFlexLayout"))) - (cond-> (cfh/text-shape? data) (crc/add-properties! {:name "characters" @@ -534,4 +565,9 @@ :set (fn [self value] (let [id (obj/get self "$id")] - (st/emit! (dwt/update-attrs id {:text-transform value}))))})))))) + (st/emit! (dwt/update-attrs id {:text-transform value}))))})) + + (cond-> (or (cfh/path-shape? data) (cfh/bool-shape? data)) + (crc/add-properties! + {:name "content" + :get #(-> % proxy->shape :content array-to-js)}))))))