mirror of
https://github.com/penpot/penpot.git
synced 2025-05-29 01:16:11 +02:00
♻️ Components refactor: move generators for duplicate
This commit is contained in:
parent
d92faaa6c6
commit
bfe9caba15
4 changed files with 304 additions and 313 deletions
|
@ -22,8 +22,10 @@
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
|
[app.common.types.page :as ctp]
|
||||||
[app.common.types.pages-list :as ctpl]
|
[app.common.types.pages-list :as ctpl]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.types.typography :as cty]
|
[app.common.types.typography :as cty]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
@ -1923,3 +1925,295 @@
|
||||||
(cond-> changes
|
(cond-> changes
|
||||||
(some? swap-slot)
|
(some? swap-slot)
|
||||||
(generate-sync-head file-full libraries container id components-v2 true))))
|
(generate-sync-head file-full libraries container id components-v2 true))))
|
||||||
|
|
||||||
|
(defn generate-duplicate-flows
|
||||||
|
[changes shapes page ids-map]
|
||||||
|
(let [flows (-> page :options :flows)
|
||||||
|
unames (volatile! (into #{} (map :name flows)))
|
||||||
|
frames-with-flow (->> shapes
|
||||||
|
(filter #(= (:type %) :frame))
|
||||||
|
(filter #(some? (ctp/get-frame-flow flows (:id %)))))]
|
||||||
|
(if-not (empty? frames-with-flow)
|
||||||
|
(let [update-flows (fn [flows]
|
||||||
|
(reduce
|
||||||
|
(fn [flows frame]
|
||||||
|
(let [name (cfh/generate-unique-name @unames "Flow 1")
|
||||||
|
_ (vswap! unames conj name)
|
||||||
|
new-flow {:id (uuid/next)
|
||||||
|
:name name
|
||||||
|
:starting-frame (get ids-map (:id frame))}]
|
||||||
|
(ctp/add-flow flows new-flow)))
|
||||||
|
flows
|
||||||
|
frames-with-flow))]
|
||||||
|
(pcb/update-page-option changes :flows update-flows))
|
||||||
|
changes)))
|
||||||
|
|
||||||
|
(defn generate-duplicate-guides
|
||||||
|
[changes shapes page ids-map delta]
|
||||||
|
(let [guides (get-in page [:options :guides])
|
||||||
|
frames (->> shapes (filter cfh/frame-shape?))
|
||||||
|
|
||||||
|
new-guides
|
||||||
|
(reduce
|
||||||
|
(fn [g frame]
|
||||||
|
(let [new-id (ids-map (:id frame))
|
||||||
|
new-frame (-> frame (gsh/move delta))
|
||||||
|
|
||||||
|
new-guides
|
||||||
|
(->> guides
|
||||||
|
(vals)
|
||||||
|
(filter #(= (:frame-id %) (:id frame)))
|
||||||
|
(map #(-> %
|
||||||
|
(assoc :id (uuid/next))
|
||||||
|
(assoc :frame-id new-id)
|
||||||
|
(assoc :position (if (= (:axis %) :x)
|
||||||
|
(+ (:position %) (- (:x new-frame) (:x frame)))
|
||||||
|
(+ (:position %) (- (:y new-frame) (:y frame))))))))]
|
||||||
|
(cond-> g
|
||||||
|
(not-empty new-guides)
|
||||||
|
(conj (into {} (map (juxt :id identity) new-guides))))))
|
||||||
|
guides
|
||||||
|
frames)]
|
||||||
|
(-> (pcb/with-page changes page)
|
||||||
|
(pcb/set-page-option :guides new-guides))))
|
||||||
|
|
||||||
|
(defn generate-duplicate-component-change
|
||||||
|
[changes objects page component-root parent-id frame-id delta libraries library-data]
|
||||||
|
(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))
|
||||||
|
origin-frame (get-in page [:objects frame-id])
|
||||||
|
delta (cond-> delta
|
||||||
|
(some? origin-frame)
|
||||||
|
(gpt/subtract (-> origin-frame :selrect gpt/point)))
|
||||||
|
|
||||||
|
instantiate-component
|
||||||
|
#(generate-instantiate-component changes
|
||||||
|
objects
|
||||||
|
file-id
|
||||||
|
(:component-id component-root)
|
||||||
|
pos
|
||||||
|
page
|
||||||
|
libraries
|
||||||
|
(:id component-root)
|
||||||
|
parent-id
|
||||||
|
frame-id
|
||||||
|
{})
|
||||||
|
|
||||||
|
restore-component
|
||||||
|
#(let [restore (prepare-restore-component changes library-data (:component-id component-root) page delta (:id component-root) parent-id frame-id)]
|
||||||
|
[(:shape restore) (:changes restore)])
|
||||||
|
|
||||||
|
[_shape changes]
|
||||||
|
(if (nil? main-component)
|
||||||
|
(restore-component)
|
||||||
|
(instantiate-component))]
|
||||||
|
changes))
|
||||||
|
|
||||||
|
(defn generate-duplicate-shape-change
|
||||||
|
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id]
|
||||||
|
(generate-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id (:frame-id obj) (:parent-id obj) false false true))
|
||||||
|
|
||||||
|
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data file-id frame-id parent-id duplicating-component? child? remove-swap-slot?]
|
||||||
|
(cond
|
||||||
|
(nil? obj)
|
||||||
|
changes
|
||||||
|
|
||||||
|
(ctf/is-main-of-known-component? obj libraries)
|
||||||
|
(generate-duplicate-component-change changes objects page obj parent-id frame-id delta libraries library-data)
|
||||||
|
|
||||||
|
:else
|
||||||
|
(let [frame? (cfh/frame-shape? obj)
|
||||||
|
group? (cfh/group-shape? obj)
|
||||||
|
bool? (cfh/bool-shape? obj)
|
||||||
|
new-id (ids-map (:id obj))
|
||||||
|
parent-id (or parent-id frame-id)
|
||||||
|
parent (get objects parent-id)
|
||||||
|
name (:name obj)
|
||||||
|
|
||||||
|
is-component-root? (or (:saved-component-root obj)
|
||||||
|
;; Backward compatibility
|
||||||
|
(:saved-component-root? obj)
|
||||||
|
(ctk/instance-root? obj))
|
||||||
|
duplicating-component? (or duplicating-component? (ctk/instance-head? obj))
|
||||||
|
is-component-main? (ctk/main-instance? obj)
|
||||||
|
subinstance-head? (ctk/subinstance-head? obj)
|
||||||
|
instance-root? (ctk/instance-root? obj)
|
||||||
|
|
||||||
|
into-component? (and duplicating-component?
|
||||||
|
(ctn/in-any-component? objects parent))
|
||||||
|
|
||||||
|
level-delta (if (some? level-delta)
|
||||||
|
level-delta
|
||||||
|
(ctn/get-nesting-level-delta objects obj parent))
|
||||||
|
new-shape-ref (ctf/advance-shape-ref nil page libraries obj level-delta {:include-deleted? true})
|
||||||
|
|
||||||
|
regenerate-component
|
||||||
|
(fn [changes shape]
|
||||||
|
(let [components-v2 (dm/get-in library-data [:options :components-v2])
|
||||||
|
[_ changes] (generate-add-component-changes changes shape objects file-id (:id page) components-v2)]
|
||||||
|
changes))
|
||||||
|
|
||||||
|
new-obj
|
||||||
|
(-> obj
|
||||||
|
(assoc :id new-id
|
||||||
|
:name name
|
||||||
|
:parent-id parent-id
|
||||||
|
:frame-id frame-id)
|
||||||
|
|
||||||
|
(cond-> (and (not instance-root?)
|
||||||
|
subinstance-head?
|
||||||
|
remove-swap-slot?)
|
||||||
|
(ctk/remove-swap-slot))
|
||||||
|
|
||||||
|
(dissoc :shapes
|
||||||
|
:use-for-thumbnail)
|
||||||
|
|
||||||
|
(cond-> (not is-component-root?)
|
||||||
|
(dissoc :main-instance))
|
||||||
|
|
||||||
|
(cond-> into-component?
|
||||||
|
(dissoc :component-root))
|
||||||
|
|
||||||
|
(cond-> (and (ctk/instance-head? obj)
|
||||||
|
(not into-component?))
|
||||||
|
(assoc :component-root true))
|
||||||
|
|
||||||
|
(cond-> (or frame? group? bool?)
|
||||||
|
(assoc :shapes []))
|
||||||
|
|
||||||
|
(cond-> (and (some? new-shape-ref)
|
||||||
|
(not= new-shape-ref (:shape-ref obj)))
|
||||||
|
(assoc :shape-ref new-shape-ref))
|
||||||
|
|
||||||
|
(gsh/move delta)
|
||||||
|
(d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))
|
||||||
|
|
||||||
|
(cond-> (ctl/grid-layout? obj)
|
||||||
|
(ctl/remap-grid-cells ids-map)))
|
||||||
|
|
||||||
|
new-obj (cond-> new-obj
|
||||||
|
(not duplicating-component?)
|
||||||
|
(ctk/detach-shape))
|
||||||
|
|
||||||
|
;; We want the first added object to touch it's parent, but not subsequent children
|
||||||
|
changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)})
|
||||||
|
(pcb/amend-last-change #(assoc % :old-id (:id obj)))
|
||||||
|
(cond-> (ctl/grid-layout? objects (:parent-id obj))
|
||||||
|
(-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells {:with-objects? true})
|
||||||
|
(pcb/reorder-grid-children [(:parent-id obj)]))))
|
||||||
|
|
||||||
|
changes (cond-> changes
|
||||||
|
(and is-component-root? is-component-main?)
|
||||||
|
(regenerate-component new-obj))
|
||||||
|
|
||||||
|
;; This is needed for the recursive call to find the new object as parent
|
||||||
|
page' (ctst/add-shape (:id new-obj)
|
||||||
|
new-obj
|
||||||
|
{:objects objects}
|
||||||
|
(:frame-id new-obj)
|
||||||
|
(:parent-id new-obj)
|
||||||
|
nil
|
||||||
|
true)]
|
||||||
|
|
||||||
|
(reduce (fn [changes child]
|
||||||
|
(generate-duplicate-shape-change changes
|
||||||
|
(:objects page')
|
||||||
|
page
|
||||||
|
unames
|
||||||
|
update-unames!
|
||||||
|
ids-map
|
||||||
|
child
|
||||||
|
delta
|
||||||
|
level-delta
|
||||||
|
libraries
|
||||||
|
library-data
|
||||||
|
file-id
|
||||||
|
(if frame? new-id frame-id)
|
||||||
|
new-id
|
||||||
|
duplicating-component?
|
||||||
|
true
|
||||||
|
(and remove-swap-slot?
|
||||||
|
;; only remove swap slot of children when the current shape
|
||||||
|
;; is not a subinstance head nor a instance root
|
||||||
|
(not subinstance-head?)
|
||||||
|
(not instance-root?))))
|
||||||
|
changes
|
||||||
|
(map (d/getf objects) (:shapes obj)))))))
|
||||||
|
|
||||||
|
(defn generate-duplicate-changes
|
||||||
|
"Prepare objects to duplicate: generate new id, give them unique names,
|
||||||
|
move to the desired position, and recalculate parents and frames as needed."
|
||||||
|
[changes all-objects page ids delta libraries library-data file-id]
|
||||||
|
(let [shapes (map (d/getf all-objects) ids)
|
||||||
|
unames (volatile! (cfh/get-used-names (:objects page)))
|
||||||
|
update-unames! (fn [new-name] (vswap! unames conj new-name))
|
||||||
|
all-ids (reduce #(into %1 (cons %2 (cfh/get-children-ids all-objects %2))) (d/ordered-set) ids)
|
||||||
|
|
||||||
|
;; We need ids-map for remapping the grid layout. But when duplicating the guides
|
||||||
|
;; we calculate a new one because the components will have created new shapes.
|
||||||
|
ids-map (into {} (map #(vector % (uuid/next))) all-ids)
|
||||||
|
|
||||||
|
changes (-> changes
|
||||||
|
(pcb/with-page page)
|
||||||
|
(pcb/with-objects all-objects))
|
||||||
|
changes
|
||||||
|
(->> shapes
|
||||||
|
(reduce #(generate-duplicate-shape-change %1
|
||||||
|
all-objects
|
||||||
|
page
|
||||||
|
unames
|
||||||
|
update-unames!
|
||||||
|
ids-map
|
||||||
|
%2
|
||||||
|
delta
|
||||||
|
nil
|
||||||
|
libraries
|
||||||
|
library-data
|
||||||
|
file-id)
|
||||||
|
changes))
|
||||||
|
|
||||||
|
;; We need to check the changes to get the ids-map
|
||||||
|
ids-map
|
||||||
|
(into {}
|
||||||
|
(comp
|
||||||
|
(filter #(= :add-obj (:type %)))
|
||||||
|
(map #(vector (:old-id %) (-> % :obj :id))))
|
||||||
|
(:redo-changes changes))]
|
||||||
|
|
||||||
|
(-> changes
|
||||||
|
(generate-duplicate-flows shapes page ids-map)
|
||||||
|
(generate-duplicate-guides shapes page ids-map delta))))
|
||||||
|
|
||||||
|
(defn generate-duplicate-changes-update-indices
|
||||||
|
"Updates the changes to correctly set the indexes of the duplicated objects,
|
||||||
|
depending on the index of the original object respect their parent."
|
||||||
|
[changes objects ids]
|
||||||
|
(let [;; index-map is a map that goes from parent-id => vector([id index-in-parent])
|
||||||
|
index-map (reduce (fn [index-map id]
|
||||||
|
(let [parent-id (get-in objects [id :parent-id])
|
||||||
|
parent-index (cfh/get-position-on-parent objects id)]
|
||||||
|
(update index-map parent-id (fnil conj []) [id parent-index])))
|
||||||
|
{}
|
||||||
|
ids)
|
||||||
|
|
||||||
|
inc-indices
|
||||||
|
(fn [[offset result] [id index]]
|
||||||
|
[(inc offset) (conj result [id (+ index offset)])])
|
||||||
|
|
||||||
|
fix-indices
|
||||||
|
(fn [_ entry]
|
||||||
|
(->> entry
|
||||||
|
(sort-by second)
|
||||||
|
(reduce inc-indices [1 []])
|
||||||
|
(second)
|
||||||
|
(into {})))
|
||||||
|
|
||||||
|
objects-indices (->> index-map (d/mapm fix-indices) (vals) (reduce merge))]
|
||||||
|
|
||||||
|
(pcb/amend-changes
|
||||||
|
changes
|
||||||
|
(fn [change]
|
||||||
|
(assoc change :index (get objects-indices (:old-id change)))))))
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
[app.common.geom.rect :as grc]
|
[app.common.geom.rect :as grc]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.geom.shapes.grid-layout :as gslg]
|
[app.common.geom.shapes.grid-layout :as gslg]
|
||||||
|
[app.common.logic.libraries :as cll]
|
||||||
[app.common.logic.shapes :as cls]
|
[app.common.logic.shapes :as cls]
|
||||||
[app.common.schema :as sm]
|
[app.common.schema :as sm]
|
||||||
[app.common.text :as txt]
|
[app.common.text :as txt]
|
||||||
|
@ -1868,7 +1869,8 @@
|
||||||
drop-cell (when (ctl/grid-layout? all-objects parent-id)
|
drop-cell (when (ctl/grid-layout? all-objects parent-id)
|
||||||
(gslg/get-drop-cell frame-id all-objects position))
|
(gslg/get-drop-cell frame-id all-objects position))
|
||||||
|
|
||||||
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries ldata file-id)
|
changes (-> (pcb/empty-changes it)
|
||||||
|
(cll/generate-duplicate-changes all-objects page selected delta libraries ldata file-id)
|
||||||
(pcb/amend-changes (partial process-rchange media-idx))
|
(pcb/amend-changes (partial process-rchange media-idx))
|
||||||
(pcb/amend-changes (partial change-add-obj-index objects selected index)))
|
(pcb/amend-changes (partial change-add-obj-index objects selected index)))
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,6 @@
|
||||||
[app.common.logic.libraries :as cll]
|
[app.common.logic.libraries :as cll]
|
||||||
[app.common.record :as cr]
|
[app.common.record :as cr]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.container :as ctn]
|
|
||||||
[app.common.types.file :as ctf]
|
|
||||||
[app.common.types.page :as ctp]
|
|
||||||
[app.common.types.shape-tree :as ctst]
|
|
||||||
[app.common.types.shape.interactions :as ctsi]
|
|
||||||
[app.common.types.shape.layout :as ctl]
|
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.modal :as md]
|
[app.main.data.modal :as md]
|
||||||
|
@ -368,308 +362,6 @@
|
||||||
(rx/of (select-shape (:id selected))))))))
|
(rx/of (select-shape (:id selected))))))))
|
||||||
|
|
||||||
;; --- Duplicate Shapes
|
;; --- Duplicate Shapes
|
||||||
(declare prepare-duplicate-shape-change)
|
|
||||||
(declare prepare-duplicate-flows)
|
|
||||||
(declare prepare-duplicate-guides)
|
|
||||||
|
|
||||||
(defn prepare-duplicate-changes
|
|
||||||
"Prepare objects to duplicate: generate new id, give them unique names,
|
|
||||||
move to the desired position, and recalculate parents and frames as needed."
|
|
||||||
([all-objects page ids delta it libraries library-data file-id]
|
|
||||||
(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 file-id init-changes)))
|
|
||||||
|
|
||||||
([all-objects page ids delta it libraries library-data file-id init-changes]
|
|
||||||
(let [shapes (map (d/getf all-objects) ids)
|
|
||||||
unames (volatile! (cfh/get-used-names (:objects page)))
|
|
||||||
update-unames! (fn [new-name] (vswap! unames conj new-name))
|
|
||||||
all-ids (reduce #(into %1 (cons %2 (cfh/get-children-ids all-objects %2))) (d/ordered-set) ids)
|
|
||||||
|
|
||||||
;; We need ids-map for remapping the grid layout. But when duplicating the guides
|
|
||||||
;; we calculate a new one because the components will have created new shapes.
|
|
||||||
ids-map (into {} (map #(vector % (uuid/next))) all-ids)
|
|
||||||
|
|
||||||
changes
|
|
||||||
(->> shapes
|
|
||||||
(reduce #(prepare-duplicate-shape-change %1
|
|
||||||
all-objects
|
|
||||||
page
|
|
||||||
unames
|
|
||||||
update-unames!
|
|
||||||
ids-map
|
|
||||||
%2
|
|
||||||
delta
|
|
||||||
nil
|
|
||||||
libraries
|
|
||||||
library-data
|
|
||||||
it
|
|
||||||
file-id)
|
|
||||||
init-changes))
|
|
||||||
|
|
||||||
;; We need to check the changes to get the ids-map
|
|
||||||
ids-map
|
|
||||||
(into {}
|
|
||||||
(comp
|
|
||||||
(filter #(= :add-obj (:type %)))
|
|
||||||
(map #(vector (:old-id %) (-> % :obj :id))))
|
|
||||||
(:redo-changes changes))]
|
|
||||||
|
|
||||||
(-> changes
|
|
||||||
(prepare-duplicate-flows shapes page ids-map)
|
|
||||||
(prepare-duplicate-guides shapes page ids-map delta)))))
|
|
||||||
|
|
||||||
(defn- prepare-duplicate-component-change
|
|
||||||
[changes objects page component-root parent-id frame-id delta libraries library-data]
|
|
||||||
(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))
|
|
||||||
origin-frame (get-in page [:objects frame-id])
|
|
||||||
delta (cond-> delta
|
|
||||||
(some? origin-frame)
|
|
||||||
(gpt/subtract (-> origin-frame :selrect gpt/point)))
|
|
||||||
|
|
||||||
instantiate-component
|
|
||||||
#(cll/generate-instantiate-component changes
|
|
||||||
objects
|
|
||||||
file-id
|
|
||||||
(:component-id component-root)
|
|
||||||
pos
|
|
||||||
page
|
|
||||||
libraries
|
|
||||||
(:id component-root)
|
|
||||||
parent-id
|
|
||||||
frame-id
|
|
||||||
{})
|
|
||||||
|
|
||||||
restore-component
|
|
||||||
#(let [restore (cll/prepare-restore-component changes library-data (:component-id component-root) page delta (:id component-root) parent-id frame-id)]
|
|
||||||
[(:shape restore) (:changes restore)])
|
|
||||||
|
|
||||||
[_shape changes]
|
|
||||||
(if (nil? main-component)
|
|
||||||
(restore-component)
|
|
||||||
(instantiate-component))]
|
|
||||||
changes))
|
|
||||||
|
|
||||||
;; TODO: move to common.files.shape-helpers
|
|
||||||
(defn- prepare-duplicate-shape-change
|
|
||||||
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id]
|
|
||||||
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false true))
|
|
||||||
|
|
||||||
([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id frame-id parent-id duplicating-component? child? remove-swap-slot?]
|
|
||||||
(cond
|
|
||||||
(nil? obj)
|
|
||||||
changes
|
|
||||||
|
|
||||||
(ctf/is-main-of-known-component? obj libraries)
|
|
||||||
(prepare-duplicate-component-change changes objects page obj parent-id frame-id delta libraries library-data)
|
|
||||||
|
|
||||||
:else
|
|
||||||
(let [frame? (cfh/frame-shape? obj)
|
|
||||||
group? (cfh/group-shape? obj)
|
|
||||||
bool? (cfh/bool-shape? obj)
|
|
||||||
new-id (ids-map (:id obj))
|
|
||||||
parent-id (or parent-id frame-id)
|
|
||||||
parent (get objects parent-id)
|
|
||||||
name (:name obj)
|
|
||||||
|
|
||||||
is-component-root? (or (:saved-component-root obj)
|
|
||||||
;; Backward compatibility
|
|
||||||
(:saved-component-root? obj)
|
|
||||||
(ctk/instance-root? obj))
|
|
||||||
duplicating-component? (or duplicating-component? (ctk/instance-head? obj))
|
|
||||||
is-component-main? (ctk/main-instance? obj)
|
|
||||||
subinstance-head? (ctk/subinstance-head? obj)
|
|
||||||
instance-root? (ctk/instance-root? obj)
|
|
||||||
|
|
||||||
into-component? (and duplicating-component?
|
|
||||||
(ctn/in-any-component? objects parent))
|
|
||||||
|
|
||||||
level-delta (if (some? level-delta)
|
|
||||||
level-delta
|
|
||||||
(ctn/get-nesting-level-delta objects obj parent))
|
|
||||||
new-shape-ref (ctf/advance-shape-ref nil page libraries obj level-delta {:include-deleted? true})
|
|
||||||
|
|
||||||
regenerate-component
|
|
||||||
(fn [changes shape]
|
|
||||||
(let [components-v2 (dm/get-in library-data [:options :components-v2])
|
|
||||||
[_ changes] (cll/generate-add-component-changes changes shape objects file-id (:id page) components-v2)]
|
|
||||||
changes))
|
|
||||||
|
|
||||||
new-obj
|
|
||||||
(-> obj
|
|
||||||
(assoc :id new-id
|
|
||||||
:name name
|
|
||||||
:parent-id parent-id
|
|
||||||
:frame-id frame-id)
|
|
||||||
|
|
||||||
(cond-> (and (not instance-root?)
|
|
||||||
subinstance-head?
|
|
||||||
remove-swap-slot?)
|
|
||||||
(ctk/remove-swap-slot))
|
|
||||||
|
|
||||||
(dissoc :shapes
|
|
||||||
:use-for-thumbnail)
|
|
||||||
|
|
||||||
(cond-> (not is-component-root?)
|
|
||||||
(dissoc :main-instance))
|
|
||||||
|
|
||||||
(cond-> into-component?
|
|
||||||
(dissoc :component-root))
|
|
||||||
|
|
||||||
(cond-> (and (ctk/instance-head? obj)
|
|
||||||
(not into-component?))
|
|
||||||
(assoc :component-root true))
|
|
||||||
|
|
||||||
(cond-> (or frame? group? bool?)
|
|
||||||
(assoc :shapes []))
|
|
||||||
|
|
||||||
(cond-> (and (some? new-shape-ref)
|
|
||||||
(not= new-shape-ref (:shape-ref obj)))
|
|
||||||
(assoc :shape-ref new-shape-ref))
|
|
||||||
|
|
||||||
(gsh/move delta)
|
|
||||||
(d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))
|
|
||||||
|
|
||||||
(cond-> (ctl/grid-layout? obj)
|
|
||||||
(ctl/remap-grid-cells ids-map)))
|
|
||||||
|
|
||||||
new-obj (cond-> new-obj
|
|
||||||
(not duplicating-component?)
|
|
||||||
(ctk/detach-shape))
|
|
||||||
|
|
||||||
;; We want the first added object to touch it's parent, but not subsequent children
|
|
||||||
changes (-> (pcb/add-object changes new-obj {:ignore-touched (and duplicating-component? child?)})
|
|
||||||
(pcb/amend-last-change #(assoc % :old-id (:id obj)))
|
|
||||||
(cond-> (ctl/grid-layout? objects (:parent-id obj))
|
|
||||||
(-> (pcb/update-shapes [(:parent-id obj)] ctl/assign-cells {:with-objects? true})
|
|
||||||
(pcb/reorder-grid-children [(:parent-id obj)]))))
|
|
||||||
|
|
||||||
changes (cond-> changes
|
|
||||||
(and is-component-root? is-component-main?)
|
|
||||||
(regenerate-component new-obj))
|
|
||||||
|
|
||||||
;; This is needed for the recursive call to find the new object as parent
|
|
||||||
page' (ctst/add-shape (:id new-obj)
|
|
||||||
new-obj
|
|
||||||
{:objects objects}
|
|
||||||
(:frame-id new-obj)
|
|
||||||
(:parent-id new-obj)
|
|
||||||
nil
|
|
||||||
true)]
|
|
||||||
|
|
||||||
(reduce (fn [changes child]
|
|
||||||
(prepare-duplicate-shape-change changes
|
|
||||||
(:objects page')
|
|
||||||
page
|
|
||||||
unames
|
|
||||||
update-unames!
|
|
||||||
ids-map
|
|
||||||
child
|
|
||||||
delta
|
|
||||||
level-delta
|
|
||||||
libraries
|
|
||||||
library-data
|
|
||||||
it
|
|
||||||
file-id
|
|
||||||
(if frame? new-id frame-id)
|
|
||||||
new-id
|
|
||||||
duplicating-component?
|
|
||||||
true
|
|
||||||
(and remove-swap-slot?
|
|
||||||
;; only remove swap slot of children when the current shape
|
|
||||||
;; is not a subinstance head nor a instance root
|
|
||||||
(not subinstance-head?)
|
|
||||||
(not instance-root?))))
|
|
||||||
changes
|
|
||||||
(map (d/getf objects) (:shapes obj)))))))
|
|
||||||
|
|
||||||
(defn- prepare-duplicate-flows
|
|
||||||
[changes shapes page ids-map]
|
|
||||||
(let [flows (-> page :options :flows)
|
|
||||||
unames (volatile! (into #{} (map :name flows)))
|
|
||||||
frames-with-flow (->> shapes
|
|
||||||
(filter #(= (:type %) :frame))
|
|
||||||
(filter #(some? (ctp/get-frame-flow flows (:id %)))))]
|
|
||||||
(if-not (empty? frames-with-flow)
|
|
||||||
(let [update-flows (fn [flows]
|
|
||||||
(reduce
|
|
||||||
(fn [flows frame]
|
|
||||||
(let [name (cfh/generate-unique-name @unames "Flow 1")
|
|
||||||
_ (vswap! unames conj name)
|
|
||||||
new-flow {:id (uuid/next)
|
|
||||||
:name name
|
|
||||||
:starting-frame (get ids-map (:id frame))}]
|
|
||||||
(ctp/add-flow flows new-flow)))
|
|
||||||
flows
|
|
||||||
frames-with-flow))]
|
|
||||||
(pcb/update-page-option changes :flows update-flows))
|
|
||||||
changes)))
|
|
||||||
|
|
||||||
(defn- prepare-duplicate-guides
|
|
||||||
[changes shapes page ids-map delta]
|
|
||||||
(let [guides (get-in page [:options :guides])
|
|
||||||
frames (->> shapes (filter cfh/frame-shape?))
|
|
||||||
|
|
||||||
new-guides
|
|
||||||
(reduce
|
|
||||||
(fn [g frame]
|
|
||||||
(let [new-id (ids-map (:id frame))
|
|
||||||
new-frame (-> frame (gsh/move delta))
|
|
||||||
|
|
||||||
new-guides
|
|
||||||
(->> guides
|
|
||||||
(vals)
|
|
||||||
(filter #(= (:frame-id %) (:id frame)))
|
|
||||||
(map #(-> %
|
|
||||||
(assoc :id (uuid/next))
|
|
||||||
(assoc :frame-id new-id)
|
|
||||||
(assoc :position (if (= (:axis %) :x)
|
|
||||||
(+ (:position %) (- (:x new-frame) (:x frame)))
|
|
||||||
(+ (:position %) (- (:y new-frame) (:y frame))))))))]
|
|
||||||
(cond-> g
|
|
||||||
(not-empty new-guides)
|
|
||||||
(conj (into {} (map (juxt :id identity) new-guides))))))
|
|
||||||
guides
|
|
||||||
frames)]
|
|
||||||
(-> (pcb/with-page changes page)
|
|
||||||
(pcb/set-page-option :guides new-guides))))
|
|
||||||
|
|
||||||
(defn duplicate-changes-update-indices
|
|
||||||
"Updates the changes to correctly set the indexes of the duplicated objects,
|
|
||||||
depending on the index of the original object respect their parent."
|
|
||||||
[objects ids changes]
|
|
||||||
(let [;; index-map is a map that goes from parent-id => vector([id index-in-parent])
|
|
||||||
index-map (reduce (fn [index-map id]
|
|
||||||
(let [parent-id (get-in objects [id :parent-id])
|
|
||||||
parent-index (cfh/get-position-on-parent objects id)]
|
|
||||||
(update index-map parent-id (fnil conj []) [id parent-index])))
|
|
||||||
{}
|
|
||||||
ids)
|
|
||||||
|
|
||||||
inc-indices
|
|
||||||
(fn [[offset result] [id index]]
|
|
||||||
[(inc offset) (conj result [id (+ index offset)])])
|
|
||||||
|
|
||||||
fix-indices
|
|
||||||
(fn [_ entry]
|
|
||||||
(->> entry
|
|
||||||
(sort-by second)
|
|
||||||
(reduce inc-indices [1 []])
|
|
||||||
(second)
|
|
||||||
(into {})))
|
|
||||||
|
|
||||||
objects-indices (->> index-map (d/mapm fix-indices) (vals) (reduce merge))]
|
|
||||||
|
|
||||||
(pcb/amend-changes
|
|
||||||
changes
|
|
||||||
(fn [change]
|
|
||||||
(assoc change :index (get objects-indices (:old-id change)))))))
|
|
||||||
|
|
||||||
(defn clear-memorize-duplicated
|
(defn clear-memorize-duplicated
|
||||||
[]
|
[]
|
||||||
|
@ -746,8 +438,9 @@
|
||||||
libraries (wsh/get-libraries state)
|
libraries (wsh/get-libraries state)
|
||||||
library-data (wsh/get-file state file-id)
|
library-data (wsh/get-file state file-id)
|
||||||
|
|
||||||
changes (->> (prepare-duplicate-changes objects page ids delta it libraries library-data file-id)
|
changes (-> (pcb/empty-changes it)
|
||||||
(duplicate-changes-update-indices objects ids))
|
(cll/generate-duplicate-changes objects page ids delta libraries library-data file-id)
|
||||||
|
(cll/generate-duplicate-changes-update-indices objects ids))
|
||||||
|
|
||||||
tags (or (:tags changes) #{})
|
tags (or (:tags changes) #{})
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.flex-layout :as flex]
|
[app.common.geom.shapes.flex-layout :as flex]
|
||||||
[app.common.geom.shapes.grid-layout :as grid]
|
[app.common.geom.shapes.grid-layout :as grid]
|
||||||
|
[app.common.logic.libraries :as cll]
|
||||||
[app.common.types.component :as ctc]
|
[app.common.types.component :as ctc]
|
||||||
[app.common.types.modifiers :as ctm]
|
[app.common.types.modifiers :as ctm]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
@ -339,8 +340,9 @@
|
||||||
selected (set shapes-by-track)
|
selected (set shapes-by-track)
|
||||||
|
|
||||||
changes
|
changes
|
||||||
(->> (dwse/prepare-duplicate-changes objects page selected (gpt/point 0 0) it libraries library-data file-id)
|
(-> (pcb/empty-changes it)
|
||||||
(dwse/duplicate-changes-update-indices objects selected))
|
(cll/generate-duplicate-changes objects page selected (gpt/point 0 0) libraries library-data file-id)
|
||||||
|
(cll/generate-duplicate-changes-update-indices objects selected))
|
||||||
|
|
||||||
;; Creates a map with shape-id => duplicated-shape-id
|
;; Creates a map with shape-id => duplicated-shape-id
|
||||||
ids-map
|
ids-map
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue