mirror of
https://github.com/penpot/penpot.git
synced 2026-05-07 09:08:33 +00:00
⚡ Translation-aware modifier propagation and lazy parent walks
This commit is contained in:
parent
9230091492
commit
97511ba6e5
@ -75,27 +75,28 @@
|
||||
(reduce check-shape changes mod-obj-changes)))
|
||||
|
||||
(defn generate-update-shapes
|
||||
[changes ids update-fn objects {:keys [attrs changed-sub-attr ignore-tree ignore-touched with-objects?]}]
|
||||
(let [changes
|
||||
(->> ids
|
||||
(reduce
|
||||
(fn [changes id]
|
||||
(let [opts {:attrs attrs
|
||||
:ignore-geometry? (get ignore-tree id)
|
||||
:ignore-touched ignore-touched
|
||||
:with-objects? with-objects?}]
|
||||
(pcb/update-shapes changes [id] update-fn (d/without-nils opts))))
|
||||
(cond-> changes
|
||||
(some? objects) (pcb/with-objects objects))))
|
||||
grid-ids
|
||||
(->> ids (filter (partial ctl/grid-layout? objects)))
|
||||
[changes ids update-fn objects {:keys [attrs changed-sub-attr ignore-tree ignore-touched with-objects? translation?]}]
|
||||
(let [changes (reduce
|
||||
(fn [changes id]
|
||||
(let [opts {:attrs attrs
|
||||
:ignore-geometry? (get ignore-tree id)
|
||||
:ignore-touched ignore-touched
|
||||
:with-objects? with-objects?}]
|
||||
(pcb/update-shapes changes [id] update-fn (d/without-nils opts))))
|
||||
(cond-> changes
|
||||
(some? objects) (pcb/with-objects objects))
|
||||
ids)
|
||||
;; Translation doesn't shift children between grid cells, so
|
||||
;; cell reassignment + child reorder are no-ops.
|
||||
grid-ids (when-not translation?
|
||||
(->> ids (filter (partial ctl/grid-layout? objects))))
|
||||
changes (cond-> changes
|
||||
(seq grid-ids)
|
||||
(-> (pcb/update-shapes grid-ids ctl/assign-cell-positions {:with-objects? true})
|
||||
(pcb/reorder-grid-children ids))
|
||||
|
||||
changes
|
||||
(-> changes
|
||||
(pcb/update-shapes grid-ids ctl/assign-cell-positions {:with-objects? true})
|
||||
(pcb/reorder-grid-children ids)
|
||||
(cond-> (not ignore-touched)
|
||||
(generate-unapply-tokens objects changed-sub-attr)))]
|
||||
(not ignore-touched)
|
||||
(generate-unapply-tokens objects changed-sub-attr))]
|
||||
changes))
|
||||
|
||||
(defn- generate-update-shape-flags
|
||||
|
||||
@ -486,53 +486,78 @@
|
||||
;; or inside its main component if it's in a copy.
|
||||
comps-nesting-loop?)))
|
||||
|
||||
(defn parent-validation-cache
|
||||
"Pre-computes the `children`-derived data for `find-valid-parent-and-frame-ids`.
|
||||
Build once per gesture and pass as `cache`; values are delays so unused
|
||||
branches stay unrealized."
|
||||
[objects children libraries]
|
||||
(let [children-ids (set (map :id children))
|
||||
top-children (remove #(contains? children-ids (:parent-id %)) children)
|
||||
all-main? (every? ctk/main-instance? top-children)
|
||||
get-variant-id (fn [shape]
|
||||
(when (:component-id shape)
|
||||
(-> (get-component-from-shape shape libraries)
|
||||
:variant-id)))
|
||||
descendants (delay (mapcat #(cfh/get-children-with-self objects %) children-ids))
|
||||
any-variant-container-descendant (delay (some ctk/is-variant-container? @descendants))
|
||||
descendants-variant-ids-set (delay (->> @descendants
|
||||
(map get-variant-id)
|
||||
set))
|
||||
any-main-descendant
|
||||
(delay
|
||||
(some
|
||||
(fn [shape]
|
||||
(some ctk/main-instance? (cfh/get-children-with-self objects (:id shape))))
|
||||
children))]
|
||||
{:top-children top-children
|
||||
:all-main? all-main?
|
||||
:descendants descendants
|
||||
:any-variant-container-descendant any-variant-container-descendant
|
||||
:descendants-variant-ids-set descendants-variant-ids-set
|
||||
:any-main-descendant any-main-descendant}))
|
||||
|
||||
(defn find-valid-parent-and-frame-ids
|
||||
"Navigate trough the ancestors until find one that is valid. Returns [ parent-id frame-id ]"
|
||||
([parent-id objects children]
|
||||
(find-valid-parent-and-frame-ids parent-id objects children false nil))
|
||||
(find-valid-parent-and-frame-ids parent-id objects children false nil nil))
|
||||
([parent-id objects children pasting? libraries]
|
||||
(find-valid-parent-and-frame-ids parent-id objects children pasting? libraries nil))
|
||||
([parent-id objects children pasting? libraries cache]
|
||||
(letfn [(get-frame [pid]
|
||||
(if (cfh/frame-shape? objects pid) pid (get-in objects [pid :frame-id])))]
|
||||
;; `descendants`, variant-id set, etc. depend only on the moved shapes, not on the
|
||||
;; candidate parent. Computing them once per drag (this fn is hot during move)
|
||||
;; avoids O(depth * subtree) work when walking invalid ancestors — common with
|
||||
;; variants and nested components.
|
||||
(let [children-ids (into #{} (map :id) children)
|
||||
top-children (remove #(contains? children-ids (:parent-id %)) children)
|
||||
all-main? (every? ctk/main-instance? top-children)
|
||||
get-variant-id
|
||||
(fn [shape]
|
||||
(when (:component-id shape)
|
||||
(-> (get-component-from-shape shape libraries)
|
||||
:variant-id)))
|
||||
descendants (mapcat #(cfh/get-children-with-self objects %) children-ids)
|
||||
any-variant-container-descendant (some ctk/is-variant-container? descendants)
|
||||
descendants-variant-ids-set (into #{} (map get-variant-id) descendants)
|
||||
;; Same as (some #(some ctk/main-instance? (cfh/get-children-with-self objects (:id %)))
|
||||
;; children) but a single walk over `descendants`.
|
||||
any-main-descendant (some ctk/main-instance? descendants)]
|
||||
;; Predicates below are ordered so cheap parent/ascendant checks
|
||||
;; short-circuit before the descendant delays are forced.
|
||||
(let [{:keys [top-children all-main? any-variant-container-descendant
|
||||
descendants-variant-ids-set any-main-descendant]}
|
||||
(or cache (parent-validation-cache objects children libraries))]
|
||||
|
||||
(loop [parent-id parent-id]
|
||||
(let [parent (get objects parent-id)
|
||||
|
||||
;; We can always move the children to the parent they already have.
|
||||
;; But if we are pasting, those are new items, so it is considered a change
|
||||
no-changes?
|
||||
(and (every? #(= parent-id (:parent-id %)) top-children)
|
||||
(not pasting?))
|
||||
|
||||
ascendants (cfh/get-parents-with-self objects parent-id)
|
||||
any-main-ascendant (some ctk/main-instance? ascendants)
|
||||
any-variant-container-ascendant (some ctk/is-variant-container? ascendants)]
|
||||
|
||||
(if (or no-changes?
|
||||
(and (not (invalid-structure-for-component? objects parent children pasting? libraries))
|
||||
;; If we are moving (not pasting) into a main component, no descendant can be main
|
||||
(or pasting? (nil? any-main-descendant) (not (ctk/main-instance? parent)))
|
||||
(or pasting? (not (ctk/main-instance? parent)) (nil? @any-main-descendant))
|
||||
;; Don't allow variant-container inside variant container nor main
|
||||
(or (not any-variant-container-descendant)
|
||||
(and (not any-variant-container-ascendant) (not any-main-ascendant)))
|
||||
(or (and (not any-variant-container-ascendant) (not any-main-ascendant))
|
||||
(not @any-variant-container-descendant))
|
||||
;; If the parent is a variant-container, all the items should be main
|
||||
(or (not (ctk/is-variant-container? parent)) all-main?)
|
||||
;; If we are pasting, the parent can't be a "brother" of any of the pasted items,
|
||||
;; so not have the same variant-id of any descendant
|
||||
(or (not pasting?)
|
||||
(not (ctk/is-variant? parent))
|
||||
(not (contains? descendants-variant-ids-set (:variant-id parent))))))
|
||||
(not (contains? @descendants-variant-ids-set (:variant-id parent))))))
|
||||
[parent-id (get-frame parent-id)]
|
||||
(recur (:parent-id parent)))))))))
|
||||
|
||||
|
||||
@ -631,9 +631,56 @@
|
||||
|
||||
(def ^:private xf:map-key (map key))
|
||||
|
||||
(defn- expand-translation-entry
|
||||
"Expand one translation-only geometry entry into [descendant-id matrix]
|
||||
pairs covering the moved shape's full subtree (every descendant gets
|
||||
the same matrix)."
|
||||
[[id data] objects subtree-ids-by-id]
|
||||
(let [m (:transform data)
|
||||
sub (or (get subtree-ids-by-id id)
|
||||
(cfh/get-children-ids-with-self objects id))]
|
||||
(map (fn [sid] [sid m]) sub)))
|
||||
|
||||
(defn- expand-translation-modifiers
|
||||
"Pure translation propagates as identity to descendants: every shape in
|
||||
the subtree gets the same matrix. Builds the flat [id matrix] list
|
||||
directly, skipping the WASM tree walk + FFI roundtrip used by
|
||||
`propagate-modifiers` for the general (resize/rotate) case.
|
||||
|
||||
Only safe when pixel-snap is off: WASM applies pixel correction
|
||||
per-shape (different scale/translation per descendant), which we
|
||||
can't replicate cheaply on the CLJS side."
|
||||
[geometry-entries objects subtree-ids-by-id]
|
||||
(into []
|
||||
(mapcat #(expand-translation-entry % objects subtree-ids-by-id))
|
||||
geometry-entries))
|
||||
|
||||
(defn- translate-selrect
|
||||
"Shift `selrect`'s center by (tx, ty). Width/height/transform are
|
||||
invariant under pure translation, so only `:center` moves."
|
||||
[selrect tx ty]
|
||||
(update selrect :center
|
||||
(fn [c] (gpt/point (+ (:x c) tx) (+ (:y c) ty)))))
|
||||
|
||||
(defn- cached-translation-selrect
|
||||
"Translation-only fast path for the live selection rect. Avoids a WASM
|
||||
`get-selection-rect` call per drag frame by caching the gesture-start
|
||||
base: on the first emission, ask WASM and back out the current delta
|
||||
to recover the base; on every later emission, shift the cached base
|
||||
by the new (tx, ty)."
|
||||
[ids ^js first-matrix cache]
|
||||
(let [tx (.-e first-matrix)
|
||||
ty (.-f first-matrix)]
|
||||
(if-let [base @cache]
|
||||
(translate-selrect base tx ty)
|
||||
(let [computed (wasm.api/get-selection-rect ids)]
|
||||
(vreset! cache (translate-selrect computed (- tx) (- ty)))
|
||||
computed))))
|
||||
|
||||
#_:clj-kondo/ignore
|
||||
(defn set-wasm-modifiers
|
||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel]
|
||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel
|
||||
subtree-ids-by-id selection-rect-cache]
|
||||
:or {ignore-constraints false ignore-snap-pixel false}
|
||||
:as params}]
|
||||
(ptk/reify ::set-wasm-modifiers
|
||||
@ -658,14 +705,24 @@
|
||||
wasm-props (:wasm-props state)
|
||||
objects (dsh/lookup-page-objects state)
|
||||
snap-pixel?
|
||||
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))]
|
||||
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))
|
||||
|
||||
translation?
|
||||
(every? #(ctm/only-move? (:modifiers %)) (vals modif-tree))]
|
||||
(set-wasm-props! objects prev-wasm-props wasm-props)
|
||||
(wasm.api/set-structure-modifiers (parse-structure-modifiers modif-tree))
|
||||
(when-not translation?
|
||||
(wasm.api/set-structure-modifiers (parse-structure-modifiers modif-tree)))
|
||||
(let [geometry-entries (parse-geometry-modifiers modif-tree)
|
||||
modifiers (wasm.api/propagate-modifiers geometry-entries snap-pixel?)]
|
||||
modifiers
|
||||
(if (and translation? (not snap-pixel?))
|
||||
(expand-translation-modifiers geometry-entries objects subtree-ids-by-id)
|
||||
(wasm.api/propagate-modifiers geometry-entries snap-pixel?))]
|
||||
(wasm.api/set-modifiers modifiers)
|
||||
(let [ids (into [] xf:map-key geometry-entries)
|
||||
selrect (wasm.api/get-selection-rect ids)]
|
||||
(let [ids (into [] xf:map-key geometry-entries)
|
||||
selrect
|
||||
(if (and translation? (not snap-pixel?) selection-rect-cache (seq modifiers))
|
||||
(cached-translation-selrect ids (second (first modifiers)) selection-rect-cache)
|
||||
(wasm.api/get-selection-rect ids))]
|
||||
(rx/of (set-temporary-selrect selrect)
|
||||
(set-temporary-modifiers modifiers))))))))
|
||||
|
||||
@ -694,92 +751,110 @@
|
||||
|
||||
#_:clj-kondo/ignore
|
||||
(defn apply-wasm-modifiers
|
||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel snap-ignore-axis undo-transation?]
|
||||
[modif-tree & {:keys [ignore-constraints ignore-snap-pixel snap-ignore-axis undo-transation?
|
||||
subtree-ids-by-id]
|
||||
:or {ignore-constraints false ignore-snap-pixel false snap-ignore-axis nil undo-transation? true}
|
||||
:as params}]
|
||||
(ptk/reify ::apply-wasm-modifiesr
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(wasm.api/clean-modifiers)
|
||||
(wasm.api/set-structure-modifiers (parse-structure-modifiers modif-tree))
|
||||
(let [translation?
|
||||
(every? #(ctm/only-move? (:modifiers %)) (vals modif-tree))]
|
||||
(wasm.api/clean-modifiers)
|
||||
(when-not translation?
|
||||
(wasm.api/set-structure-modifiers (parse-structure-modifiers modif-tree)))
|
||||
|
||||
;; Apply property changes (e.g. grow-type) to WASM shapes before
|
||||
;; propagating geometry, so propagate_modifiers sees the updated state.
|
||||
(doseq [[id {:keys [property value]}] (extract-property-changes modif-tree)]
|
||||
(when (= property :grow-type)
|
||||
(wasm.api/use-shape id)
|
||||
(wasm.api/set-shape-grow-type value)))
|
||||
;; Apply property changes (e.g. grow-type) to WASM shapes before
|
||||
;; propagating geometry, so propagate_modifiers sees the updated state.
|
||||
(doseq [[id {:keys [property value]}] (extract-property-changes modif-tree)]
|
||||
(when (= property :grow-type)
|
||||
(wasm.api/use-shape id)
|
||||
(wasm.api/set-shape-grow-type value)))
|
||||
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
|
||||
geometry-entries
|
||||
(parse-geometry-modifiers modif-tree)
|
||||
geometry-entries
|
||||
(parse-geometry-modifiers modif-tree)
|
||||
|
||||
snap-pixel?
|
||||
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))
|
||||
snap-pixel?
|
||||
(and (not ignore-snap-pixel) (contains? (:workspace-layout state) :snap-pixel-grid))
|
||||
|
||||
transforms
|
||||
(into {} (wasm.api/propagate-modifiers geometry-entries snap-pixel?))
|
||||
transforms
|
||||
(if (and translation? (not snap-pixel?))
|
||||
;; Mirror WASM `propagate_modifiers` in CLJS: splat the
|
||||
;; translation matrix onto every descendant. Without
|
||||
;; this step the commit would only touch the dragged
|
||||
;; primaries and descendants would snap back to their
|
||||
;; pre-drag positions on drop.
|
||||
;;
|
||||
;; Skipped when `snap-pixel?` is on: WASM applies
|
||||
;; per-shape pixel correction (different scale/translate
|
||||
;; per descendant) which we can't replicate cheaply on
|
||||
;; the CLJS side.
|
||||
(reduce
|
||||
(fn [acc [id data]]
|
||||
(let [t (:transform data)
|
||||
subtree-ids
|
||||
(or (get subtree-ids-by-id id)
|
||||
(cfh/get-children-ids-with-self objects id))]
|
||||
(reduce (fn [a sid] (assoc a sid t)) acc subtree-ids)))
|
||||
{}
|
||||
geometry-entries)
|
||||
(into {} (wasm.api/propagate-modifiers geometry-entries snap-pixel?)))
|
||||
|
||||
;; Pure-translation gesture: every shape's modifier only
|
||||
;; contains `:move` operations (no resize/rotate/scale and
|
||||
;; no structural mutation)
|
||||
translation?
|
||||
(every? #(ctm/only-move? (:modifiers %)) (vals modif-tree))
|
||||
ignore-tree
|
||||
(calculate-ignore-tree-wasm transforms objects)
|
||||
|
||||
ignore-tree
|
||||
(calculate-ignore-tree-wasm transforms objects)
|
||||
options
|
||||
(-> params
|
||||
(assoc :reg-objects? true)
|
||||
(assoc :ignore-tree ignore-tree)
|
||||
(assoc :translation? translation?)
|
||||
;; Attributes that can change in the transform. This
|
||||
;; way we don't have to check all the attributes
|
||||
(assoc :attrs transform-attrs))
|
||||
|
||||
options
|
||||
(-> params
|
||||
(assoc :reg-objects? true)
|
||||
(assoc :ignore-tree ignore-tree)
|
||||
(assoc :translation? translation?)
|
||||
;; Attributes that can change in the transform. This
|
||||
;; way we don't have to check all the attributes
|
||||
(assoc :attrs transform-attrs))
|
||||
modif-tree
|
||||
(propagate-structure-modifiers modif-tree (dsh/lookup-page-objects state))
|
||||
|
||||
modif-tree
|
||||
(propagate-structure-modifiers modif-tree (dsh/lookup-page-objects state))
|
||||
ids
|
||||
(into (set (keys modif-tree)) xf:without-uuid-zero (keys transforms))
|
||||
|
||||
ids
|
||||
(into (set (keys modif-tree)) xf:without-uuid-zero (keys transforms))
|
||||
update-shape
|
||||
(fn [shape]
|
||||
(let [shape-id (dm/get-prop shape :id)
|
||||
transform (get transforms shape-id)
|
||||
modifiers (dm/get-in modif-tree [shape-id :modifiers])]
|
||||
(-> shape
|
||||
(gsh/apply-transform transform)
|
||||
(ctm/apply-structure-modifiers modifiers))))
|
||||
|
||||
update-shape
|
||||
(fn [shape]
|
||||
(let [shape-id (dm/get-prop shape :id)
|
||||
transform (get transforms shape-id)
|
||||
modifiers (dm/get-in modif-tree [shape-id :modifiers])]
|
||||
(-> shape
|
||||
(gsh/apply-transform transform)
|
||||
(ctm/apply-structure-modifiers modifiers))))
|
||||
bool-ids
|
||||
(into #{}
|
||||
(comp
|
||||
(mapcat (partial cfh/get-parents-with-self objects))
|
||||
(filter cfh/bool-shape?)
|
||||
(map :id))
|
||||
ids)
|
||||
|
||||
bool-ids
|
||||
(into #{}
|
||||
(comp
|
||||
(mapcat (partial cfh/get-parents-with-self objects))
|
||||
(filter cfh/bool-shape?)
|
||||
(map :id))
|
||||
ids)
|
||||
undo-id (js/Symbol)]
|
||||
(rx/concat
|
||||
(if undo-transation?
|
||||
(rx/of (dwu/start-undo-transaction undo-id))
|
||||
(rx/empty))
|
||||
(rx/of
|
||||
(clear-local-transform)
|
||||
(ptk/event ::dwg/move-frame-guides {:ids ids :transforms transforms})
|
||||
(ptk/event ::dwcm/move-frame-comment-threads transforms)
|
||||
(dwsh/update-shapes ids update-shape options)
|
||||
|
||||
undo-id (js/Symbol)]
|
||||
(rx/concat
|
||||
(if undo-transation?
|
||||
(rx/of (dwu/start-undo-transaction undo-id))
|
||||
(rx/empty))
|
||||
(rx/of
|
||||
(clear-local-transform)
|
||||
(ptk/event ::dwg/move-frame-guides {:ids ids :transforms transforms})
|
||||
(ptk/event ::dwcm/move-frame-comment-threads transforms)
|
||||
(dwsh/update-shapes ids update-shape options)
|
||||
;; The update to the bool path needs to be in a different operation because it
|
||||
;; needs to have the updated children info
|
||||
(dwsh/update-shapes bool-ids path/update-bool-shape (assoc options :with-objects? true)))
|
||||
|
||||
;; The update to the bool path needs to be in a different operation because it
|
||||
;; needs to have the updated children info
|
||||
(dwsh/update-shapes bool-ids path/update-bool-shape (assoc options :with-objects? true)))
|
||||
|
||||
(if undo-transation?
|
||||
(rx/of (dwu/commit-undo-transaction undo-id))
|
||||
(rx/empty)))))))
|
||||
(if undo-transation?
|
||||
(rx/of (dwu/commit-undo-transaction undo-id))
|
||||
(rx/empty))))))))
|
||||
|
||||
(def ^:private
|
||||
xf-rotation-shape
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
|
||||
;; If anything a translation can mutate is added here, drop the
|
||||
;; `(when-not translation? …)` guard in `update-shapes` below.
|
||||
(def ^:private update-layout-attr? #{:hidden})
|
||||
|
||||
(defn- add-undo-group
|
||||
@ -180,8 +182,9 @@
|
||||
(map :id))
|
||||
|
||||
update-layout-ids
|
||||
(->> (into [] xf-update-layout ids)
|
||||
(not-empty))
|
||||
(when-not translation?
|
||||
(->> (into [] xf-update-layout ids)
|
||||
(not-empty)))
|
||||
|
||||
changes
|
||||
(-> (pcb/empty-changes it page-id)
|
||||
@ -194,7 +197,8 @@
|
||||
:changed-sub-attr changed-sub-attr
|
||||
:ignore-tree ignore-tree
|
||||
:ignore-touched ignore-touched
|
||||
:with-objects? with-objects?})
|
||||
:with-objects? with-objects?
|
||||
:translation? translation?})
|
||||
(cond-> undo-group
|
||||
(pcb/set-undo-group undo-group))
|
||||
(pcb/set-translation? translation?))
|
||||
|
||||
@ -658,10 +658,6 @@
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [prev-cell-data (volatile! nil)
|
||||
;; Cache the resolved valid parent while hovering the same raw target frame.
|
||||
;; `find-valid-parent-and-frame-ids` may walk many ancestors for variants/components,
|
||||
;; and the result is stable during the gesture (objects/libraries are constant here).
|
||||
find-valid-for-raw-cache (volatile! {:raw nil :pair nil})
|
||||
page-id (:current-page-id state)
|
||||
libraries (dsh/lookup-libraries state)
|
||||
objects (dsh/lookup-page-objects state page-id)
|
||||
@ -708,7 +704,21 @@
|
||||
(rx/map #(array pos %)))))))]
|
||||
(if (empty? shapes)
|
||||
(rx/of (finish-transform))
|
||||
(let [move-stream
|
||||
;; Per-gesture caches: `shapes`/`objects`/`libraries` are
|
||||
;; stable for the gesture, so build once and thread through.
|
||||
(let [parent-validation-cache
|
||||
(ctn/parent-validation-cache objects shapes libraries)
|
||||
|
||||
subtree-ids-by-id
|
||||
(into {}
|
||||
(map (fn [id]
|
||||
[id (cfh/get-children-ids-with-self objects id)]))
|
||||
ids)
|
||||
|
||||
selection-rect-cache
|
||||
(volatile! nil)
|
||||
|
||||
move-stream
|
||||
(->> position
|
||||
;; We ask for the snap position but we continue even if the result is not available
|
||||
(rx/with-latest-from snap-delta)
|
||||
@ -722,14 +732,8 @@
|
||||
(fn [[move-vector mod?]]
|
||||
(let [position (gpt/add from-position move-vector)
|
||||
exclude-frames (if mod? exclude-frames exclude-frames-siblings)
|
||||
raw-target (ctst/top-nested-frame objects position exclude-frames)
|
||||
cache @find-valid-for-raw-cache
|
||||
[target-frame _]
|
||||
(if (= raw-target (:raw cache))
|
||||
(:pair cache)
|
||||
(let [pair (ctn/find-valid-parent-and-frame-ids raw-target objects shapes false libraries)]
|
||||
(vreset! find-valid-for-raw-cache {:raw raw-target :pair pair})
|
||||
pair))
|
||||
target-frame (ctst/top-nested-frame objects position exclude-frames)
|
||||
[target-frame _] (ctn/find-valid-parent-and-frame-ids target-frame objects shapes false libraries parent-validation-cache)
|
||||
flex-layout? (ctl/flex-layout? objects target-frame)
|
||||
grid-layout? (ctl/grid-layout? objects target-frame)
|
||||
drop-index (when flex-layout? (gslf/get-drop-index target-frame objects position))
|
||||
@ -782,7 +786,10 @@
|
||||
(rx/sample 16)
|
||||
(rx/map
|
||||
(fn [[modifiers snap-ignore-axis]]
|
||||
(dwm/set-wasm-modifiers modifiers :snap-ignore-axis snap-ignore-axis))))
|
||||
(dwm/set-wasm-modifiers modifiers
|
||||
:snap-ignore-axis snap-ignore-axis
|
||||
:subtree-ids-by-id subtree-ids-by-id
|
||||
:selection-rect-cache selection-rect-cache))))
|
||||
|
||||
(->> move-stream
|
||||
(rx/with-latest-from ms/mouse-position-alt)
|
||||
@ -807,7 +814,8 @@
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwm/apply-wasm-modifiers modifiers
|
||||
:snap-ignore-axis snap-ignore-axis
|
||||
:undo-transation? false)
|
||||
:undo-transation? false
|
||||
:subtree-ids-by-id subtree-ids-by-id)
|
||||
(move-shapes-to-frame ids target-frame drop-index drop-cell)
|
||||
(finish-transform)
|
||||
(dwu/commit-undo-transaction undo-id))))))))
|
||||
|
||||
@ -75,6 +75,11 @@
|
||||
(track! :set-structure-modifiers)
|
||||
nil)
|
||||
|
||||
(defn- mock-set-modifiers
|
||||
[_modifiers]
|
||||
(track! :set-modifiers)
|
||||
nil)
|
||||
|
||||
(defn- mock-set-shape-grow-type
|
||||
[_grow-type]
|
||||
(track! :set-shape-grow-type)
|
||||
@ -141,6 +146,7 @@
|
||||
{:clean-modifiers wasm.api/clean-modifiers
|
||||
:set-structure-modifiers wasm.api/set-structure-modifiers
|
||||
:propagate-modifiers wasm.api/propagate-modifiers
|
||||
:set-modifiers wasm.api/set-modifiers
|
||||
:set-shape-grow-type wasm.api/set-shape-grow-type
|
||||
:set-shape-text-content wasm.api/set-shape-text-content
|
||||
:set-shape-text-images wasm.api/set-shape-text-images
|
||||
@ -152,6 +158,7 @@
|
||||
(set! wasm.api/clean-modifiers mock-clean-modifiers)
|
||||
(set! wasm.api/set-structure-modifiers mock-set-structure-modifiers)
|
||||
(set! wasm.api/propagate-modifiers mock-propagate-modifiers)
|
||||
(set! wasm.api/set-modifiers mock-set-modifiers)
|
||||
(set! wasm.api/set-shape-grow-type mock-set-shape-grow-type)
|
||||
(set! wasm.api/set-shape-text-content mock-set-shape-text-content)
|
||||
(set! wasm.api/set-shape-text-images mock-set-shape-text-images)
|
||||
@ -167,6 +174,7 @@
|
||||
(set! wasm.api/clean-modifiers (:clean-modifiers orig))
|
||||
(set! wasm.api/set-structure-modifiers (:set-structure-modifiers orig))
|
||||
(set! wasm.api/propagate-modifiers (:propagate-modifiers orig))
|
||||
(set! wasm.api/set-modifiers (:set-modifiers orig))
|
||||
(set! wasm.api/set-shape-grow-type (:set-shape-grow-type orig))
|
||||
(set! wasm.api/set-shape-text-content (:set-shape-text-content orig))
|
||||
(set! wasm.api/set-shape-text-images (:set-shape-text-images orig))
|
||||
|
||||
@ -56,10 +56,13 @@
|
||||
;; guide has moved
|
||||
(t/is (= (:position guide') 100))
|
||||
|
||||
;; WASM mocks were exercised
|
||||
(t/is (pos? (thw/call-count :clean-modifiers)))
|
||||
(t/is (pos? (thw/call-count :set-structure-modifiers)))
|
||||
(t/is (pos? (thw/call-count :propagate-modifiers)))))))))))
|
||||
;; WASM bridge was exercised. `dw/update-position`
|
||||
;; routes through `apply-wasm-modifiers`, which for
|
||||
;; translation-only updates calls only `clean-modifiers`
|
||||
;; and computes the per-descendant transforms in CLJS
|
||||
;; (skipping `set-structure-modifiers` and
|
||||
;; `propagate-modifiers`).
|
||||
(t/is (pos? (thw/call-count :clean-modifiers)))))))))))
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user