From 9243ba937d99be869a8a7a57d45c2d02a5657292 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Tue, 30 Apr 2024 11:34:50 +0200 Subject: [PATCH] :sparkles: Add to plugins clone and remove --- .../app/main/data/workspace/selection.cljs | 112 ++++++++++-------- frontend/src/app/plugins/shape.cljs | 16 ++- frontend/src/app/plugins/utils.cljs | 28 +++-- frontend/src/app/plugins/viewport.cljs | 27 +++-- 4 files changed, 112 insertions(+), 71 deletions(-) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index d13921687..b271f1ae6 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -723,62 +723,76 @@ (gpt/subtract new-pos pt-obj))))) +(defn duplicate-shapes + [ids & {:keys [move-delta? alt-duplication? change-selection? return-ref] + :or {move-delta? false alt-duplication? false change-selection? true return-ref nil}}] + (ptk/reify ::duplicate-shapes + ptk/WatchEvent + (watch [it state _] + (let [page (wsh/lookup-page state) + objects (:objects page) + ids (into #{} + (comp (map (d/getf objects)) + (filter #(ctk/allow-duplicate? objects %)) + (map :id)) + ids)] + (when (seq ids) + (let [obj (get objects (first ids)) + delta (if move-delta? + (calc-duplicate-delta obj state objects) + (gpt/point 0 0)) + + file-id (:current-file-id state) + libraries (wsh/get-libraries state) + library-data (wsh/get-file state file-id) + + changes (->> (prepare-duplicate-changes objects page ids delta it libraries library-data file-id) + (duplicate-changes-update-indices objects ids)) + + tags (or (:tags changes) #{}) + + changes (cond-> changes alt-duplication? (assoc :tags (conj tags :alt-duplication))) + + id-original (first ids) + + new-ids (->> changes + :redo-changes + (filter #(= (:type %) :add-obj)) + (filter #(ids (:old-id %))) + (map #(get-in % [:obj :id])) + (into (d/ordered-set))) + + id-duplicated (first new-ids) + + frames (into #{} + (map #(get-in objects [% :frame-id])) + ids) + undo-id (js/Symbol)] + + ;; Warning: This order is important for the focus mode. + (->> (rx/of + (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (when change-selection? + (select-shapes new-ids)) + (ptk/data-event :layout/update {:ids frames}) + (memorize-duplicated id-original id-duplicated) + (dwu/commit-undo-transaction undo-id)) + (rx/tap #(when (some? return-ref) + (reset! return-ref id-duplicated)))))))))) + (defn duplicate-selected ([move-delta?] (duplicate-selected move-delta? false)) ([move-delta? alt-duplication?] (ptk/reify ::duplicate-selected ptk/WatchEvent - (watch [it state _] + (watch [_ state _] (when (or (not move-delta?) (nil? (get-in state [:workspace-local :transform]))) - (let [page (wsh/lookup-page state) - objects (:objects page) - selected (->> (wsh/lookup-selected state) - (map (d/getf objects)) - (filter #(ctk/allow-duplicate? objects %)) - (map :id) - set)] - (when (seq selected) - (let [obj (get objects (first selected)) - delta (if move-delta? - (calc-duplicate-delta obj state objects) - (gpt/point 0 0)) - - file-id (:current-file-id state) - libraries (wsh/get-libraries state) - library-data (wsh/get-file state file-id) - - changes (->> (prepare-duplicate-changes objects page selected delta it libraries library-data file-id) - (duplicate-changes-update-indices objects selected)) - - tags (or (:tags changes) #{}) - - changes (cond-> changes alt-duplication? (assoc :tags (conj tags :alt-duplication))) - - id-original (first selected) - - new-selected (->> changes - :redo-changes - (filter #(= (:type %) :add-obj)) - (filter #(selected (:old-id %))) - (map #(get-in % [:obj :id])) - (into (d/ordered-set))) - - id-duplicated (first new-selected) - - frames (into #{} - (map #(get-in objects [% :frame-id])) - selected) - undo-id (js/Symbol)] - - ;; Warning: This order is important for the focus mode. - (rx/of - (dwu/start-undo-transaction undo-id) - (dch/commit-changes changes) - (select-shapes new-selected) - (ptk/data-event :layout/update {:ids frames}) - (memorize-duplicated id-original id-duplicated) - (dwu/commit-undo-transaction undo-id)))))))))) + (let [selected (wsh/lookup-selected state)] + (rx/of (duplicate-shapes selected + :move-delta? move-delta? + :alt-duplication? alt-duplication?)))))))) (defn change-hover-state [id value] diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index e285efc9a..b537109d7 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -15,6 +15,8 @@ [app.common.uuid :as uuid] [app.main.data.workspace :as udw] [app.main.data.workspace.changes :as dwc] + [app.main.data.workspace.selection :as dws] + [app.main.data.workspace.shapes :as dwsh] [app.main.store :as st] [app.plugins.utils :as utils :refer [get-data get-data-fn]] [app.util.object :as obj])) @@ -61,8 +63,18 @@ (st/emit! (udw/update-dimensions [id] :width width) (udw/update-dimensions [id] :height height)))) - (clone [_] (.log js/console (clj->js _data))) - (delete [_] (.log js/console (clj->js _data))) + (clone [self] + (let [id (get-data self :id) + page-id (:current-page-id @st/state) + ret-v (atom nil)] + (st/emit! (dws/duplicate-shapes #{id} :change-selection? false :return-ref ret-v)) + (let [new-id (deref ret-v) + shape (dm/get-in @st/state [:workspace-data :pages-index page-id :objects new-id])] + (data->shape-proxy shape)))) + + (remove [self] + (let [id (get-data self :id)] + (st/emit! (dwsh/delete-shapes #{id})))) (appendChild [self child] (let [parent-id (get-data self :id) diff --git a/frontend/src/app/plugins/utils.cljs b/frontend/src/app/plugins/utils.cljs index 32add7bfd..23d8f276a 100644 --- a/frontend/src/app/plugins/utils.cljs +++ b/frontend/src/app/plugins/utils.cljs @@ -8,12 +8,11 @@ "RPC for plugins runtime." (:require [app.common.data.macros :as dm] + [app.common.spec :as us] [app.common.uuid :as uuid] [app.util.object :as obj] - [cuerdas.core :as str])) - -(def uuid-regex - #"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}") + [cuerdas.core :as str] + [promesa.core :as p])) (defn get-data ([self attr] @@ -42,7 +41,7 @@ (let [v (cond (map? v) (from-js v) - (and (string? v) (re-matches uuid-regex v)) + (and (string? v) (re-matches us/uuid-rx v)) (uuid/uuid v) :else v)] @@ -50,7 +49,6 @@ {} ret))) - (defn to-js "Converts to javascript an camelize the keys" [obj] @@ -65,5 +63,19 @@ obj)] (clj->js result))) - - +(defn result-p + "Creates a pair of atom+promise. The promise will be resolved when the atom gets a value. + We use this to return the promise to the library clients and resolve its value when a value is passed + to the atom" + [] + (let [ret-v (atom nil) + ret-p + (p/create + (fn [resolve _] + (add-watch + ret-v + ::watcher + (fn [_ _ _ value] + (remove-watch ret-v ::watcher) + (resolve value)))))] + [ret-v ret-p])) diff --git a/frontend/src/app/plugins/viewport.cljs b/frontend/src/app/plugins/viewport.cljs index 8d647042a..656a65674 100644 --- a/frontend/src/app/plugins/viewport.cljs +++ b/frontend/src/app/plugins/viewport.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dm] [app.common.record :as crc] + [app.common.spec :as us] [app.common.uuid :as uuid] [app.main.data.workspace.viewport :as dwv] [app.main.data.workspace.zoom :as dwz] @@ -46,16 +47,17 @@ :set (fn [_ value] (let [new-x (obj/get value "x") - new-y (obj/get value "y") - vb (dm/get-in @st/state [:workspace-local :vbox]) - old-x (+ (:x vb) (/ (:width vb) 2)) - old-y (+ (:y vb) (/ (:height vb) 2)) - delta-x (- new-x old-x) - delta-y (- new-y old-y) - to-position - {:x #(+ % delta-x) - :y #(+ % delta-y)}] - (st/emit! (dwv/update-viewport-position to-position))))} + new-y (obj/get value "y")] + (when (and (us/safe-number? new-x) (us/safe-number? new-y)) + (let [vb (dm/get-in @st/state [:workspace-local :vbox]) + old-x (+ (:x vb) (/ (:width vb) 2)) + old-y (+ (:y vb) (/ (:height vb) 2)) + delta-x (- new-x old-x) + delta-y (- new-y old-y) + to-position + {:x #(+ % delta-x) + :y #(+ % delta-y)}] + (st/emit! (dwv/update-viewport-position to-position))))))} {:name "zoom" :get @@ -63,8 +65,9 @@ (dm/get-in @st/state [:workspace-local :zoom])) :set (fn [_ value] - (let [z (dm/get-in @st/state [:workspace-local :zoom])] - (st/emit! (dwz/set-zoom (/ value z)))))} + (when (us/safe-number? value) + (let [z (dm/get-in @st/state [:workspace-local :zoom])] + (st/emit! (dwz/set-zoom (/ value z))))))} {:name "bounds" :get