🎉 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]
(restore-component changes id nil))
([changes id page-id]
(assert-library changes) (assert-library changes)
(-> changes (-> changes
(update :redo-changes conj {:type :restore-component (update :redo-changes conj {:type :restore-component
:id id}) :id id
:page-id page-id})
(update :undo-changes d/preconj {:type :del-component (update :undo-changes d/preconj {:type :del-component
:id id}))) :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]
(let [components-v2 (dm/get-in file-data [:options :components-v2])
update-page? (and components-v2 (not (nil? page-id)))]
(-> file-data (-> file-data
(ctkl/update-component component-id #(dissoc % :objects)) (ctkl/update-component component-id #(dissoc % :objects))
(ctkl/mark-component-undeleted component-id))) (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)
@ -437,18 +436,10 @@
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)
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)))))) (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
in the given file library. Then selects the newly created instance." in the given file library. Then selects the newly created instance."
@ -476,7 +467,6 @@
(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,7 +146,10 @@
(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]
(generate-instantiate-component changes file-id component-id position page libraries nil))
([changes file-id component-id position page libraries old-id]
(let [component (ctf/get-component libraries file-id component-id) (let [component (ctf/get-component libraries file-id component-id)
library (get libraries file-id) library (get libraries file-id)
@ -159,11 +162,14 @@
position position
components-v2) components-v2)
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 (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
changes changes
new-shapes)] (rest new-shapes))]
[new-shape changes])) [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,18 +333,20 @@
(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 [init-changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/with-objects all-objects))]
(prepare-duplicate-changes all-objects page ids delta it libraries library-data init-changes)))
([all-objects page ids delta it libraries library-data init-changes]
(let [shapes (map (d/getf all-objects) ids) (let [shapes (map (d/getf all-objects) ids)
unames (volatile! (cp/retrieve-used-names (:objects page))) unames (volatile! (cp/retrieve-used-names (:objects page)))
update-unames! (fn [new-name] (vswap! unames conj new-name)) 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) 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) ids-map (into {} (map #(vector % (uuid/next))) all-ids)
init-changes
(-> (pcb/empty-changes it)
(pcb/with-page page)
(pcb/with-objects all-objects))
changes changes
(->> shapes (->> shapes
(reduce #(prepare-duplicate-shape-change %1 (reduce #(prepare-duplicate-shape-change %1
@ -354,31 +357,53 @@
ids-map ids-map
%2 %2
delta delta
libraries) libraries
library-data
it)
init-changes))] 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)
@ -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)))