mirror of
https://github.com/penpot/penpot.git
synced 2025-05-10 18:16:37 +02:00
🎉 Improve sync algorithm when swapped copies
This commit is contained in:
parent
0d1af260a4
commit
07939d11dc
5 changed files with 227 additions and 59 deletions
|
@ -52,7 +52,7 @@
|
|||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
||||
(log/set-level! :warn)
|
||||
(log/set-level! :trace)
|
||||
|
||||
(defn- log-changes
|
||||
[changes file]
|
||||
|
@ -870,16 +870,12 @@
|
|||
0)))))
|
||||
|
||||
(defn- add-component-for-swap
|
||||
[shape file-id id-new-component index target-cell keep-props-values {:keys [undo-group]}]
|
||||
[shape file page libraries id-new-component index target-cell keep-props-values {:keys [undo-group]}]
|
||||
(dm/assert! (uuid? id-new-component))
|
||||
(dm/assert! (uuid? file-id))
|
||||
(ptk/reify ::add-component-for-swap
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [page (wsh/lookup-page state)
|
||||
libraries (wsh/get-libraries state)
|
||||
|
||||
objects (:objects page)
|
||||
(watch [it _ _]
|
||||
(let [objects (:objects page)
|
||||
position (gpt/point (:x shape) (:y shape))
|
||||
changes (-> (pcb/empty-changes it (:id page))
|
||||
(pcb/set-undo-group undo-group)
|
||||
|
@ -889,7 +885,7 @@
|
|||
[new-shape changes]
|
||||
(dwlh/generate-instantiate-component changes
|
||||
objects
|
||||
file-id
|
||||
(:id file)
|
||||
id-new-component
|
||||
position
|
||||
page
|
||||
|
@ -898,6 +894,16 @@
|
|||
(:parent-id shape)
|
||||
(:frame-id shape))
|
||||
|
||||
new-shape (cond-> new-shape
|
||||
(nil? (ctk/get-swap-slot new-shape))
|
||||
(update :touched cfh/set-touched-group (-> (ctf/find-swap-slot shape
|
||||
page
|
||||
{:id (:id file)
|
||||
:data file}
|
||||
libraries)
|
||||
(ctk/build-swap-slot-group))))
|
||||
|
||||
;; _ (js/console.log "new-shape" (str (:id new-shape)) (clj->js new-shape))
|
||||
changes
|
||||
(-> changes
|
||||
;; Restore the properties
|
||||
|
@ -905,7 +911,11 @@
|
|||
|
||||
;; We need to set the same index as the original shape
|
||||
(pcb/change-parent (:parent-id shape) [new-shape] index {:component-swap true
|
||||
:ignore-touched true}))]
|
||||
:ignore-touched true})
|
||||
(dwlh/change-touched new-shape
|
||||
shape
|
||||
(ctn/make-container page :page)
|
||||
{}))]
|
||||
|
||||
;; First delete so we don't break the grid layout cells
|
||||
(rx/of (dch/commit-changes changes)
|
||||
|
@ -921,7 +931,10 @@
|
|||
(watch [_ state _]
|
||||
;; First delete shapes so we have space in the layout otherwise we can have problems
|
||||
;; in the grid creating new rows/columns to make space
|
||||
(let [objects (wsh/lookup-page-objects state)
|
||||
(let [file (wsh/get-file state file-id)
|
||||
libraries (wsh/get-libraries state)
|
||||
page (wsh/lookup-page state)
|
||||
objects (wsh/lookup-page-objects state)
|
||||
parent (get objects (:parent-id shape))
|
||||
|
||||
;; If the target parent is a grid layout we need to pass the target cell
|
||||
|
@ -941,7 +954,7 @@
|
|||
(dwsh/delete-shapes nil (d/ordered-set (:id shape)) {:component-swap true
|
||||
:undo-id undo-id
|
||||
:undo-group undo-group})
|
||||
(add-component-for-swap shape file-id id-new-component index target-cell keep-props-values
|
||||
(add-component-for-swap shape file page libraries id-new-component index target-cell keep-props-values
|
||||
{:undo-group undo-group})
|
||||
(ptk/data-event :layout/update [(:parent-id shape)])
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
@ -958,8 +971,12 @@
|
|||
{::ev/name "component-swap"})
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(watch [_ state _]
|
||||
(let [undo-id (js/Symbol)]
|
||||
(log/info :msg "COMPONENT-SWAP"
|
||||
:file (dwlh/pretty-file file-id state)
|
||||
:id-new-component id-new-component
|
||||
:undo-id undo-id)
|
||||
(rx/concat
|
||||
(rx/of (dwu/start-undo-transaction undo-id))
|
||||
(rx/map #(component-swap % file-id id-new-component) (rx/from shapes))
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
[clojure.set :as set]))
|
||||
|
||||
;; Change this to :info :debug or :trace to debug this module, or :warn to reset to default
|
||||
(log/set-level! :warn)
|
||||
(log/set-level! :trace)
|
||||
|
||||
(declare generate-sync-container)
|
||||
(declare generate-sync-shape)
|
||||
|
@ -594,7 +594,7 @@
|
|||
"Generate changes to synchronize one shape that is the root of a component
|
||||
instance, and all its children, from the given component."
|
||||
[changes libraries container shape-id reset? components-v2]
|
||||
(log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?)
|
||||
(log/debug :msg "Sync shape direct" :shape-inst (str shape-id) :reset? reset?)
|
||||
(let [shape-inst (ctn/get-shape container shape-id)
|
||||
library (dm/get-in libraries [(:component-file shape-inst) :data])
|
||||
component (ctkl/get-component library (:component-id shape-inst) true)]
|
||||
|
@ -656,7 +656,7 @@
|
|||
(defn- generate-sync-shape-direct-recursive
|
||||
[changes container shape-inst component library shape-main root-inst root-main reset? initial-root? redirect-shaperef components-v2]
|
||||
(log/debug :msg "Sync shape direct recursive"
|
||||
:shape (str (:name shape-inst))
|
||||
:shape-inst (str (:name shape-inst) " " (pretty-uuid (:id shape-inst)))
|
||||
:component (:name component))
|
||||
|
||||
(if (nil? shape-main)
|
||||
|
@ -713,6 +713,8 @@
|
|||
(map #(redirect-shaperef %) children-inst) children-inst)
|
||||
|
||||
only-inst (fn [changes child-inst]
|
||||
(log/trace :msg "Only inst"
|
||||
:child-inst (str (:name child-inst) " " (pretty-uuid (:id child-inst))))
|
||||
(if-not (and omit-touched?
|
||||
(contains? (:touched shape-inst)
|
||||
:shapes-group))
|
||||
|
@ -723,6 +725,8 @@
|
|||
changes))
|
||||
|
||||
only-main (fn [changes child-main]
|
||||
(log/trace :msg "Only main"
|
||||
:child-main (str (:name child-main) " " (pretty-uuid (:id child-main))))
|
||||
(if-not (and omit-touched?
|
||||
(contains? (:touched shape-inst)
|
||||
:shapes-group))
|
||||
|
@ -739,6 +743,9 @@
|
|||
changes))
|
||||
|
||||
both (fn [changes child-inst child-main]
|
||||
(log/trace :msg "Both"
|
||||
:child-inst (str (:name child-inst) " " (pretty-uuid (:id child-inst)))
|
||||
:child-main (str (:name child-main) " " (pretty-uuid (:id child-main))))
|
||||
(generate-sync-shape-direct-recursive changes
|
||||
container
|
||||
child-inst
|
||||
|
@ -753,6 +760,9 @@
|
|||
components-v2))
|
||||
|
||||
moved (fn [changes child-inst child-main]
|
||||
(log/trace :msg "Move"
|
||||
:child-inst (str (:name child-inst) " " (pretty-uuid (:id child-inst)))
|
||||
:child-main (str (:name child-main) " " (pretty-uuid (:id child-main))))
|
||||
(move-shape
|
||||
changes
|
||||
child-inst
|
||||
|
@ -768,7 +778,8 @@
|
|||
only-main
|
||||
both
|
||||
moved
|
||||
false))))
|
||||
false
|
||||
reset?))))
|
||||
|
||||
|
||||
(defn- generate-rename-component
|
||||
|
@ -939,6 +950,7 @@
|
|||
only-main
|
||||
both
|
||||
moved
|
||||
true
|
||||
true)
|
||||
|
||||
;; The inverse sync may be made on a component that is inside a
|
||||
|
@ -957,12 +969,15 @@
|
|||
;; ---- Operation generation helpers ----
|
||||
|
||||
(defn- compare-children
|
||||
[changes children-inst children-main only-inst-cb only-main-cb both-cb moved-cb inverse?]
|
||||
[changes children-inst children-main only-inst-cb only-main-cb both-cb moved-cb inverse? reset?]
|
||||
(log/trace :msg "Compare children")
|
||||
(loop [children-inst (seq (or children-inst []))
|
||||
children-main (seq (or children-main []))
|
||||
changes changes]
|
||||
(let [child-inst (first children-inst)
|
||||
child-main (first children-main)]
|
||||
(log/trace :main (str (:name child-main) " " (pretty-uuid (:id child-main)))
|
||||
:inst (str (:name child-inst) " " (pretty-uuid (:id child-inst))))
|
||||
(cond
|
||||
(and (nil? child-inst) (nil? child-main))
|
||||
changes
|
||||
|
@ -979,31 +994,58 @@
|
|||
(next children-main)
|
||||
(both-cb changes child-inst child-main))
|
||||
|
||||
(let [child-inst' (d/seek #(ctk/is-main-of? child-main %) children-inst)
|
||||
child-main' (d/seek #(ctk/is-main-of? % child-inst) children-main)]
|
||||
(cond
|
||||
(nil? child-inst')
|
||||
(recur children-inst
|
||||
(next children-main)
|
||||
(only-main-cb changes child-main))
|
||||
|
||||
(nil? child-main')
|
||||
(if (and (ctk/match-swap-slot? child-main child-inst) (not reset?))
|
||||
(do
|
||||
(log/trace :msg "Match slot"
|
||||
:shape-inst (str (:name child-inst) " " (pretty-uuid (:id child-inst)))
|
||||
:shape-main (str (:name child-main) " " (pretty-uuid (:id child-main))))
|
||||
(recur (next children-inst)
|
||||
children-main
|
||||
(only-inst-cb changes child-inst))
|
||||
(next children-main)
|
||||
changes))
|
||||
|
||||
:else
|
||||
(if inverse?
|
||||
(recur (next children-inst)
|
||||
(remove #(= (:id %) (:id child-main')) children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst child-main')
|
||||
(moved-cb child-inst child-main')))
|
||||
(recur (remove #(= (:id %) (:id child-inst')) children-inst)
|
||||
(next children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst' child-main)
|
||||
(moved-cb child-inst' child-main)))))))))))
|
||||
(let [child-inst' (d/seek #(ctk/is-main-of? child-main %) children-inst)
|
||||
child-main' (d/seek #(ctk/is-main-of? % child-inst) children-main)]
|
||||
(cond
|
||||
(nil? child-inst')
|
||||
(let [matching-inst (d/seek #(ctk/match-swap-slot? % child-main) children-inst)]
|
||||
(if (and (some? matching-inst) (not reset?))
|
||||
(do
|
||||
(log/trace :msg "Match slot inst"
|
||||
:shape-inst (str (:name child-inst') " " (pretty-uuid (:id child-inst')))
|
||||
:shape-main (str (:name child-main) " " (pretty-uuid (:id child-main))))
|
||||
(recur (remove #(= (:id %) (:id matching-inst)) children-inst)
|
||||
(next children-main)
|
||||
changes))
|
||||
(recur children-inst
|
||||
(next children-main)
|
||||
(only-main-cb changes child-main))))
|
||||
|
||||
(nil? child-main')
|
||||
(let [matching-main (d/seek #(ctk/match-swap-slot? child-inst %) children-main)]
|
||||
(if (and (some? matching-main) (not reset?))
|
||||
(do
|
||||
(log/trace :msg "Match slot main"
|
||||
:shape-inst (str (:name child-inst) " " (pretty-uuid (:id child-inst)))
|
||||
:shape-main (str (:name child-main') " " (pretty-uuid (:id child-main'))))
|
||||
(recur (next children-inst)
|
||||
(remove #(= (:id %) (:id matching-main)) children-inst)
|
||||
changes))
|
||||
(recur (next children-inst)
|
||||
children-main
|
||||
(only-inst-cb changes child-inst))))
|
||||
|
||||
:else
|
||||
(if inverse?
|
||||
(recur (next children-inst)
|
||||
(remove #(= (:id %) (:id child-main')) children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst child-main')
|
||||
(moved-cb child-inst child-main')))
|
||||
(recur (remove #(= (:id %) (:id child-inst')) children-inst)
|
||||
(next children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst' child-main)
|
||||
(moved-cb child-inst' child-main))))))))))))
|
||||
|
||||
(defn- add-shape-to-instance
|
||||
[changes component-shape index component-page container root-instance root-main omit-touched? set-remote-synced?]
|
||||
|
@ -1033,7 +1075,8 @@
|
|||
(assoc :remote-synced true)
|
||||
|
||||
:always
|
||||
(assoc :shape-ref (:id original-shape)))))
|
||||
(-> (assoc :shape-ref (:id original-shape))
|
||||
(dissoc :touched))))) ; New shape, by definition, is synced to the main shape
|
||||
|
||||
update-original-shape (fn [original-shape _new-shape]
|
||||
original-shape)
|
||||
|
@ -1270,11 +1313,10 @@
|
|||
changes
|
||||
changes')))
|
||||
|
||||
(defn- change-touched
|
||||
(defn change-touched
|
||||
[changes dest-shape origin-shape container
|
||||
{:keys [reset-touched? copy-touched?] :as options}]
|
||||
(if (or (nil? (:shape-ref dest-shape))
|
||||
(not (or reset-touched? copy-touched?)))
|
||||
(if (nil? (:shape-ref dest-shape))
|
||||
changes
|
||||
(do
|
||||
(log/info :msg (str "CHANGE-TOUCHED "
|
||||
|
@ -1287,12 +1329,16 @@
|
|||
(let [new-touched (cond
|
||||
reset-touched?
|
||||
nil
|
||||
|
||||
copy-touched?
|
||||
(if (:remote-synced origin-shape)
|
||||
nil
|
||||
(set/union
|
||||
(:touched dest-shape)
|
||||
(:touched origin-shape))))]
|
||||
(:touched origin-shape)))
|
||||
|
||||
:else
|
||||
(:touched dest-shape))]
|
||||
|
||||
(-> changes
|
||||
(update :redo-changes conj (make-change
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue