🎉 Copy paste components, even to another page

This commit is contained in:
Pablo Alba 2023-03-21 12:10:14 +01:00 committed by Andrés Moya
parent b73ce14560
commit b33e469501
7 changed files with 143 additions and 85 deletions

View file

@ -326,8 +326,8 @@
(ctf/delete-component data id skip-undelete?)) (ctf/delete-component data id skip-undelete?))
(defmethod process-change :restore-component (defmethod process-change :restore-component
[data {:keys [id]}] [data {:keys [id page-id]}]
(ctf/restore-component data id)) (ctf/restore-component data id page-id))
(defmethod process-change :purge-component (defmethod process-change :purge-component
[data {:keys [id]}] [data {:keys [id]}]

View file

@ -656,13 +656,16 @@
:id id}))) :id id})))
(defn restore-component (defn restore-component
[changes id] ([changes id]
(assert-library changes) (restore-component changes id nil))
(-> changes ([changes id page-id]
(update :redo-changes conj {:type :restore-component (assert-library changes)
:id id}) (-> changes
(update :undo-changes d/preconj {:type :del-component (update :redo-changes conj {:type :restore-component
:id id}))) :id id
:page-id page-id})
(update :undo-changes d/preconj {:type :del-component
:id id}))))
(defn ignore-remote (defn ignore-remote
[changes] [changes]

View file

@ -201,10 +201,14 @@
(defn restore-component (defn restore-component
"Recover a deleted component and all its shapes and put all this again in place." "Recover a deleted component and all its shapes and put all this again in place."
[file-data component-id] [file-data component-id page-id]
(-> file-data (let [components-v2 (dm/get-in file-data [:options :components-v2])
(ctkl/update-component component-id #(dissoc % :objects)) update-page? (and components-v2 (not (nil? page-id)))]
(ctkl/mark-component-undeleted component-id))) (-> file-data
(ctkl/update-component component-id #(dissoc % :objects))
(ctkl/mark-component-undeleted component-id)
(cond-> update-page?
(ctkl/update-component component-id #(assoc % :main-instance-page page-id))))))
(defn purge-component (defn purge-component
"Remove permanently a component." "Remove permanently a component."
@ -383,7 +387,6 @@
(some? (:component-file %)) (some? (:component-file %))
(assoc :component-file (:id file-data))) (assoc :component-file (:id file-data)))
main-instance-shapes) main-instance-shapes)
; Add all shapes of the main instance to the library page ; Add all shapes of the main instance to the library page
add-main-instance-shapes add-main-instance-shapes
(fn [page] (fn [page]

View file

@ -1600,9 +1600,10 @@
(gpt/subtract (gpt/point (:selrect base)) orig-pos))] (gpt/subtract (gpt/point (:selrect base)) orig-pos))]
[frame-id parent-id delta index])))) [frame-id parent-id delta index]))))
;; Change the indexes if the paste is done with an element selected ;; Change the indexes of the pasted shapes
(change-add-obj-index [paste-objects selected index change] (change-add-obj-index [paste-objects selected index change]
(let [set-index (fn [[result index] id] (let [index (or index -1) ;; if there is no current element selected, we want the first (inc index) to be 0
set-index (fn [[result index] id]
[(assoc result id index) (inc index)]) [(assoc result id index) (inc index)])
map-ids map-ids
@ -1626,7 +1627,8 @@
;; Proceed with the standard shape paste process. ;; Proceed with the standard shape paste process.
(do-paste [it state mouse-pos media] (do-paste [it state mouse-pos media]
(let [file-id (:current-file-id state) (let [libraries (wsh/get-libraries state)
file-id (:current-file-id state)
page (wsh/lookup-page state) page (wsh/lookup-page state)
media-idx (d/index-by :prev-id media) media-idx (d/index-by :prev-id media)
@ -1651,7 +1653,9 @@
all-objects (merge (:objects page) paste-objects) all-objects (merge (:objects page) paste-objects)
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it nil) library-data (wsh/get-file state file-id)
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries library-data)
(pcb/amend-changes (partial process-rchange media-idx)) (pcb/amend-changes (partial process-rchange media-idx))
(pcb/amend-changes (partial change-add-obj-index paste-objects selected index))) (pcb/amend-changes (partial change-add-obj-index paste-objects selected index)))

View file

@ -152,7 +152,6 @@
changes (-> (pcb/empty-changes it) changes (-> (pcb/empty-changes it)
(pcb/with-library-data data) (pcb/with-library-data data)
(pcb/update-color color)) (pcb/update-color color))
undo-id (js/Symbol)] undo-id (js/Symbol)]
(rx/of (dwu/start-undo-transaction undo-id) (rx/of (dwu/start-undo-transaction undo-id)
(dch/commit-changes changes) (dch/commit-changes changes)
@ -436,18 +435,10 @@
(ptk/reify ::restore-component (ptk/reify ::restore-component
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [library-data (wsh/get-file state library-id) (let [library-data (wsh/get-file state library-id)
component (ctkl/get-deleted-component library-data component-id) changes (:changes (dwlh/prepare-restore-component library-data component-id it))]
page (ctf/get-component-page library-data component) (rx/of (dch/commit-changes changes))))))
shapes (cph/get-children-with-self (:objects component) (:main-instance-id component))
changes (-> (pcb/empty-changes it)
(pcb/with-library-data library-data)
(pcb/with-page page))
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes
shapes)
changes (pcb/restore-component changes component-id)]
(rx/of (dch/commit-changes changes))))))
(defn instantiate-component (defn instantiate-component
"Create a new shape in the current page, from the component with the given id "Create a new shape in the current page, from the component with the given id
@ -475,8 +466,7 @@
(rx/of (dwu/start-undo-transaction undo-id) (rx/of (dwu/start-undo-transaction undo-id)
(dch/commit-changes changes) (dch/commit-changes changes)
(ptk/data-event :layout/update [(:id new-shape)]) (ptk/data-event :layout/update [(:id new-shape)])
(dws/select-shapes (d/ordered-set (:id new-shape))) (dws/select-shapes (d/ordered-set (:id new-shape)))
(dwu/commit-undo-transaction undo-id)))))) (dwu/commit-undo-transaction undo-id))))))
(defn detach-component (defn detach-component

View file

@ -146,24 +146,30 @@
(defn generate-instantiate-component (defn generate-instantiate-component
"Generate changes to create a new instance from a component." "Generate changes to create a new instance from a component."
[changes file-id component-id position page libraries] ([changes file-id component-id position page libraries]
(let [component (ctf/get-component libraries file-id component-id) (generate-instantiate-component changes file-id component-id position page libraries nil))
library (get libraries file-id)
components-v2 (dm/get-in library [:data :options :components-v2]) ([changes file-id component-id position page libraries old-id]
(let [component (ctf/get-component libraries file-id component-id)
library (get libraries file-id)
[new-shape new-shapes] components-v2 (dm/get-in library [:data :options :components-v2])
(ctn/make-component-instance page
component
(:data library)
position
components-v2)
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true}) [new-shape new-shapes]
changes (ctn/make-component-instance page
new-shapes)] component
(:data library)
position
components-v2)
[new-shape changes])) changes (cond-> (pcb/add-object changes (first new-shapes) {:ignore-touched true})
(some? old-id) (pcb/amend-last-change #(assoc % :old-id old-id))) ; on copy/paste old id is used later to reorder the paster layers
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes
(rest new-shapes))]
[new-shape changes])))
(defn generate-detach-instance (defn generate-detach-instance
"Generate changes to remove the links between a shape and all its children "Generate changes to remove the links between a shape and all its children
@ -185,6 +191,29 @@
(pcb/update-shapes changes shapes update-fn))) (pcb/update-shapes changes shapes update-fn)))
(defn prepare-restore-component
([library-data component-id it]
(let [component (ctkl/get-deleted-component library-data component-id)
page (ctf/get-component-page library-data component)]
(prepare-restore-component library-data component-id it page (gpt/point 0 0) nil nil)))
([library-data component-id it page delta old-id changes]
(let [component (ctkl/get-deleted-component library-data component-id)
shapes (cph/get-children-with-self (:objects component) (:main-instance-id component))
shapes (map #(gsh/move % delta) shapes)
changes (-> (or changes (pcb/empty-changes it))
(pcb/with-page page)
(pcb/with-library-data library-data))
changes (cond-> (pcb/add-object changes (first shapes) {:ignore-touched true})
(some? old-id) (pcb/amend-last-change #(assoc % :old-id old-id))) ; on copy/paste old id is used later to reorder the paster layers
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes
(rest shapes))]
{:changes (pcb/restore-component changes component-id (:id page))
:shape (first shapes)})))
;; ---- General library synchronization functions ---- ;; ---- General library synchronization functions ----
(defn generate-sync-file (defn generate-sync-file

View file

@ -15,6 +15,7 @@
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.file :as ctf]
[app.common.types.page :as ctp] [app.common.types.page :as ctp]
[app.common.types.shape.interactions :as ctsi] [app.common.types.shape.interactions :as ctsi]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -332,54 +333,78 @@
(defn prepare-duplicate-changes (defn prepare-duplicate-changes
"Prepare objects to duplicate: generate new id, give them unique names, "Prepare objects to duplicate: generate new id, give them unique names,
move to the desired position, and recalculate parents and frames as needed." move to the desired position, and recalculate parents and frames as needed."
[all-objects page ids delta it libraries] ([all-objects page ids delta it libraries library-data]
(let [shapes (map (d/getf all-objects) ids) (let [init-changes
unames (volatile! (cp/retrieve-used-names (:objects page))) (-> (pcb/empty-changes it)
update-unames! (fn [new-name] (vswap! unames conj new-name)) (pcb/with-page page)
all-ids (reduce #(into %1 (cons %2 (cph/get-children-ids all-objects %2))) (d/ordered-set) ids) (pcb/with-objects all-objects))]
ids-map (into {} (map #(vector % (uuid/next))) all-ids) (prepare-duplicate-changes all-objects page ids delta it libraries library-data init-changes)))
init-changes ([all-objects page ids delta it libraries library-data init-changes]
(-> (pcb/empty-changes it) (let [shapes (map (d/getf all-objects) ids)
(pcb/with-page page) unames (volatile! (cp/retrieve-used-names (:objects page)))
(pcb/with-objects all-objects)) update-unames! (fn [new-name] (vswap! unames conj new-name))
all-ids (reduce #(into %1 (cons %2 (cph/get-children-ids all-objects %2))) (d/ordered-set) ids)
ids-map (into {} (map #(vector % (uuid/next))) all-ids)
changes changes
(->> shapes (->> shapes
(reduce #(prepare-duplicate-shape-change %1 (reduce #(prepare-duplicate-shape-change %1
all-objects all-objects
page page
unames unames
update-unames! update-unames!
ids-map ids-map
%2 %2
delta delta
libraries) libraries
init-changes))] library-data
it)
init-changes))]
(-> changes (-> changes
(prepare-duplicate-flows shapes page ids-map) (prepare-duplicate-flows shapes page ids-map)
(prepare-duplicate-guides shapes page ids-map delta)))) (prepare-duplicate-guides shapes page ids-map delta)))))
(defn- prepare-duplicate-component-change
([changes page component-root delta libraries library-data it]
(let [component-id (:component-id component-root)
file-id (:component-file component-root)
main-component (ctf/get-component libraries file-id component-id)
moved-component (gsh/move component-root delta)
pos (gpt/point (:x moved-component) (:y moved-component))
instantiate-component
#(dwlh/generate-instantiate-component changes
file-id
(:component-id component-root)
pos
page
libraries
(:id component-root))
restore-component
#(let [restore (dwlh/prepare-restore-component library-data (:component-id component-root) it page delta (:id component-root) changes)]
[(:shape restore) (:changes restore)])
[_shape changes]
(if (nil? main-component)
(restore-component)
(instantiate-component))]
changes)))
(defn- prepare-duplicate-shape-change (defn- prepare-duplicate-shape-change
([changes objects page unames update-unames! ids-map obj delta libraries] ([changes objects page unames update-unames! ids-map obj delta libraries library-data it]
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries (:frame-id obj) (:parent-id obj))) (prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it (:frame-id obj) (:parent-id obj)))
([changes objects page unames update-unames! ids-map obj delta libraries frame-id parent-id] ([changes objects page unames update-unames! ids-map obj delta libraries library-data it frame-id parent-id]
(cond (cond
(nil? obj) (nil? obj)
changes changes
(ctk/main-instance? obj) (ctk/main-instance? obj)
(let [[_new-shape changes] (prepare-duplicate-component-change changes page obj delta libraries library-data it)
(dwlh/generate-instantiate-component changes
(:component-file obj)
(:component-id obj)
(gpt/point (:x obj) (:y obj))
page
libraries)]
changes)
:else :else
(let [frame? (cph/frame-shape? obj) (let [frame? (cph/frame-shape? obj)
new-id (ids-map (:id obj)) new-id (ids-map (:id obj))
@ -410,6 +435,8 @@
child child
delta delta
libraries libraries
library-data
it
(if frame? new-id frame-id) (if frame? new-id frame-id)
new-id)) new-id))
changes changes
@ -562,9 +589,11 @@
(calc-duplicate-delta obj state objects) (calc-duplicate-delta obj state objects)
(gpt/point 0 0)) (gpt/point 0 0))
file-id (:current-file-id state)
libraries (wsh/get-libraries state) libraries (wsh/get-libraries state)
library-data (wsh/get-file state file-id)
changes (->> (prepare-duplicate-changes objects page selected delta it libraries) changes (->> (prepare-duplicate-changes objects page selected delta it libraries library-data)
(duplicate-changes-update-indices objects selected)) (duplicate-changes-update-indices objects selected))
changes (cond-> changes add-undo-group? (assoc :undo-group (uuid/random))) changes (cond-> changes add-undo-group? (assoc :undo-group (uuid/random)))