mirror of
https://github.com/penpot/penpot.git
synced 2025-01-22 14:39:45 -05: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.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.typography :as cty]
|
||||
[app.common.uuid :as uuid]
|
||||
|
@ -1923,3 +1925,295 @@
|
|||
(cond-> changes
|
||||
(some? swap-slot)
|
||||
(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.shapes :as gsh]
|
||||
[app.common.geom.shapes.grid-layout :as gslg]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.text :as txt]
|
||||
|
@ -1868,7 +1869,8 @@
|
|||
drop-cell (when (ctl/grid-layout? all-objects parent-id)
|
||||
(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 change-add-obj-index objects selected index)))
|
||||
|
||||
|
|
|
@ -17,12 +17,6 @@
|
|||
[app.common.logic.libraries :as cll]
|
||||
[app.common.record :as cr]
|
||||
[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.main.data.events :as ev]
|
||||
[app.main.data.modal :as md]
|
||||
|
@ -368,308 +362,6 @@
|
|||
(rx/of (select-shape (:id selected))))))))
|
||||
|
||||
;; --- 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
|
||||
[]
|
||||
|
@ -746,8 +438,9 @@
|
|||
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))
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(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) #{})
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes.flex-layout :as flex]
|
||||
[app.common.geom.shapes.grid-layout :as grid]
|
||||
[app.common.logic.libraries :as cll]
|
||||
[app.common.types.component :as ctc]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
|
@ -339,8 +340,9 @@
|
|||
selected (set shapes-by-track)
|
||||
|
||||
changes
|
||||
(->> (dwse/prepare-duplicate-changes objects page selected (gpt/point 0 0) it libraries library-data file-id)
|
||||
(dwse/duplicate-changes-update-indices objects selected))
|
||||
(-> (pcb/empty-changes it)
|
||||
(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
|
||||
ids-map
|
||||
|
|
Loading…
Add table
Reference in a new issue