mirror of
https://github.com/penpot/penpot.git
synced 2026-08-01 10:56:20 +00:00
wip
This commit is contained in:
parent
790dfb04f0
commit
f00a334e9d
@ -46,6 +46,13 @@
|
|||||||
;; `set-wasm-modifiers` calls fire in between.
|
;; `set-wasm-modifiers` calls fire in between.
|
||||||
(defonce ^:private interactive-transform-active? (atom false))
|
(defonce ^:private interactive-transform-active? (atom false))
|
||||||
|
|
||||||
|
;; Holds the property changes (`extract-property-changes` output)
|
||||||
|
;; applied during the in-flight gesture. Written per drag frame in
|
||||||
|
;; `set-wasm-modifiers`, read at gesture-end (`clear-local-transform`)
|
||||||
|
;; to revert. Kept out of Redux to avoid root-atom churn at drag
|
||||||
|
;; cadence (~62.5 Hz) and the re-frame subscription scan that follows.
|
||||||
|
(defonce ^:private gesture-wasm-props (volatile! nil))
|
||||||
|
|
||||||
(defn- ensure-interactive-transform-start!
|
(defn- ensure-interactive-transform-start!
|
||||||
[]
|
[]
|
||||||
(when (compare-and-set! interactive-transform-active? false true)
|
(when (compare-and-set! interactive-transform-active? false true)
|
||||||
@ -303,12 +310,14 @@
|
|||||||
;; skip shadows / blur).
|
;; skip shadows / blur).
|
||||||
(ensure-interactive-transform-end!)
|
(ensure-interactive-transform-end!)
|
||||||
(wasm.api/clean-modifiers)
|
(wasm.api/clean-modifiers)
|
||||||
(set-wasm-props! (dsh/lookup-page-objects state) (:wasm-props state) [])))
|
(let [last-wasm-props @gesture-wasm-props]
|
||||||
|
(vreset! gesture-wasm-props nil)
|
||||||
|
(set-wasm-props! (dsh/lookup-page-objects state) last-wasm-props []))))
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(-> state
|
(-> state
|
||||||
(dissoc :workspace-modifiers :wasm-props :prev-wasm-props)
|
(dissoc :workspace-modifiers)
|
||||||
(dissoc :app.main.data.workspace.transforms/current-move-selected)))))
|
(dissoc :app.main.data.workspace.transforms/current-move-selected)))))
|
||||||
|
|
||||||
(defn create-modif-tree
|
(defn create-modif-tree
|
||||||
@ -684,14 +693,6 @@
|
|||||||
:or {ignore-constraints false ignore-snap-pixel false}
|
:or {ignore-constraints false ignore-snap-pixel false}
|
||||||
:as params}]
|
:as params}]
|
||||||
(ptk/reify ::set-wasm-modifiers
|
(ptk/reify ::set-wasm-modifiers
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(let [property-changes
|
|
||||||
(extract-property-changes modif-tree)]
|
|
||||||
(-> state
|
|
||||||
(assoc :prev-wasm-props (:wasm-props state))
|
|
||||||
(assoc :wasm-props property-changes))))
|
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
;; Entering an interactive transform (drag/resize/rotate). Flip
|
;; Entering an interactive transform (drag/resize/rotate). Flip
|
||||||
@ -701,8 +702,9 @@
|
|||||||
;; `clear-local-transform`.
|
;; `clear-local-transform`.
|
||||||
(ensure-interactive-transform-start!)
|
(ensure-interactive-transform-start!)
|
||||||
(wasm.api/clean-modifiers)
|
(wasm.api/clean-modifiers)
|
||||||
(let [prev-wasm-props (:prev-wasm-props state)
|
(let [prev-wasm-props @gesture-wasm-props
|
||||||
wasm-props (:wasm-props state)
|
wasm-props (extract-property-changes modif-tree)
|
||||||
|
_ (vreset! gesture-wasm-props wasm-props)
|
||||||
objects (dsh/lookup-page-objects state)
|
objects (dsh/lookup-page-objects state)
|
||||||
snap-pixel?
|
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))
|
||||||
|
|||||||
@ -743,31 +743,44 @@
|
|||||||
(rx/take-until stopper)
|
(rx/take-until stopper)
|
||||||
(rx/share))
|
(rx/share))
|
||||||
|
|
||||||
modifiers-stream
|
;; Per-pointermove: combine inputs and cache the most-recent
|
||||||
|
;; non-nil grid cell. The tap fires per move so the cache stays
|
||||||
|
;; fresh regardless of where the WASM render branch samples.
|
||||||
|
move-stream-with-cell-data
|
||||||
(->> move-stream
|
(->> move-stream
|
||||||
(rx/with-latest-from array/conj ms/mouse-position-shift)
|
(rx/with-latest-from array/conj ms/mouse-position-shift)
|
||||||
(rx/tap
|
(rx/tap
|
||||||
(fn [[_ _ _ cell-data _]]
|
(fn [[_ _ _ cell-data _]]
|
||||||
(when (some? cell-data)
|
(when (some? cell-data)
|
||||||
(vreset! prev-cell-data cell-data))))
|
(vreset! prev-cell-data cell-data))))
|
||||||
|
(rx/share))
|
||||||
|
|
||||||
(rx/map
|
;; Heavy build (modifier tree construction). Pulled out as a
|
||||||
(fn [[move-vector target-frame drop-index cell-data shift?]]
|
;; standalone fn so the WASM render branch can apply it post-
|
||||||
(let [cell-data (or cell-data @prev-cell-data)
|
;; sample and the commit branch can apply it once on the final
|
||||||
x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector)))
|
;; event, rather than running it per pointermove via the shared
|
||||||
[move-vector snap-ignore-axis]
|
;; modifiers-stream below.
|
||||||
(cond
|
build-modifier
|
||||||
(and shift? x-disp?)
|
(fn [[move-vector target-frame drop-index cell-data shift?]]
|
||||||
[(assoc move-vector :y 0) :y]
|
(let [cell-data (or cell-data @prev-cell-data)
|
||||||
|
x-disp? (> (mth/abs (:x move-vector)) (mth/abs (:y move-vector)))
|
||||||
|
[move-vector snap-ignore-axis]
|
||||||
|
(cond
|
||||||
|
(and shift? x-disp?)
|
||||||
|
[(assoc move-vector :y 0) :y]
|
||||||
|
|
||||||
shift?
|
shift?
|
||||||
[(assoc move-vector :x 0) :x]
|
[(assoc move-vector :x 0) :x]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[move-vector nil])]
|
[move-vector nil])]
|
||||||
[(-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector))
|
[(-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector))
|
||||||
(dwm/build-change-frame-modifiers objects selected target-frame drop-index cell-data))
|
(dwm/build-change-frame-modifiers objects selected target-frame drop-index cell-data))
|
||||||
snap-ignore-axis])))
|
snap-ignore-axis]))
|
||||||
|
|
||||||
|
modifiers-stream
|
||||||
|
(->> move-stream-with-cell-data
|
||||||
|
(rx/map build-modifier)
|
||||||
(rx/share))]
|
(rx/share))]
|
||||||
|
|
||||||
(if (features/active-feature? state "render-wasm/v1")
|
(if (features/active-feature? state "render-wasm/v1")
|
||||||
@ -779,11 +792,14 @@
|
|||||||
(rx/of true)
|
(rx/of true)
|
||||||
(rx/empty)))))]
|
(rx/empty)))))]
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(->> modifiers-stream
|
;; Sampled render path: `build-modifier` runs only for sampled
|
||||||
|
;; events (~62.5 Hz), not per pointermove. Modifier-tree
|
||||||
|
;; construction and frame-modifier propagation are skipped on
|
||||||
|
;; dropped frames.
|
||||||
|
(->> move-stream-with-cell-data
|
||||||
(rx/take-until duplicate-stopper)
|
(rx/take-until duplicate-stopper)
|
||||||
;; Sample at a fixed cadence to keep preview smooth. Unlike a throttle,
|
|
||||||
;; this tends to avoid perceptible "jumps" while still capping WASM work.
|
|
||||||
(rx/sample 16)
|
(rx/sample 16)
|
||||||
|
(rx/map build-modifier)
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [[modifiers snap-ignore-axis]]
|
(fn [[modifiers snap-ignore-axis]]
|
||||||
(dwm/set-wasm-modifiers modifiers
|
(dwm/set-wasm-modifiers modifiers
|
||||||
@ -802,14 +818,18 @@
|
|||||||
(dws/duplicate-selected false true))
|
(dws/duplicate-selected false true))
|
||||||
(rx/empty)))))
|
(rx/empty)))))
|
||||||
|
|
||||||
;; Last event will write the modifiers creating the changes
|
;; Last event writes the modifiers creating the changes.
|
||||||
(->> move-stream
|
;; Build from the final move event directly so the commit
|
||||||
|
;; reflects the user's actual release position rather than
|
||||||
|
;; the latest sampled value (which can be ~16 ms stale).
|
||||||
|
(->> move-stream-with-cell-data
|
||||||
(rx/last)
|
(rx/last)
|
||||||
(rx/take-until duplicate-stopper)
|
(rx/take-until duplicate-stopper)
|
||||||
(rx/with-latest-from modifiers-stream)
|
|
||||||
(rx/mapcat
|
(rx/mapcat
|
||||||
(fn [[[_ target-frame drop-index drop-cell] [modifiers snap-ignore-axis]]]
|
(fn [args]
|
||||||
(let [undo-id (js/Symbol)]
|
(let [[_ target-frame drop-index drop-cell _] args
|
||||||
|
[modifiers snap-ignore-axis] (build-modifier args)
|
||||||
|
undo-id (js/Symbol)]
|
||||||
(rx/of
|
(rx/of
|
||||||
(dwu/start-undo-transaction undo-id)
|
(dwu/start-undo-transaction undo-id)
|
||||||
(dwm/apply-wasm-modifiers modifiers
|
(dwm/apply-wasm-modifiers modifiers
|
||||||
|
|||||||
@ -388,9 +388,50 @@
|
|||||||
(def workspace-wasm-editor-styles
|
(def workspace-wasm-editor-styles
|
||||||
(l/derived :workspace-wasm-editor-styles st/state))
|
(l/derived :workspace-wasm-editor-styles st/state))
|
||||||
|
|
||||||
|
(def ^:private wasm-modifier-jitter-threshold-px
|
||||||
|
;; Suppress drag-preview pushes whose translation delta is below half a
|
||||||
|
;; pixel. The Skia renderer keeps running at full sample cadence; this
|
||||||
|
;; only coarsens the JS-side outline geometry recompute that the memoed
|
||||||
|
;; consumers in `viewport_wasm` derive from `wasm-modifiers`.
|
||||||
|
0.5)
|
||||||
|
|
||||||
|
(defn- ^boolean wasm-modifiers-significant-change?
|
||||||
|
"Cheap predicate: did `new` move any shape by ≥ threshold pixels vs `prev`.
|
||||||
|
Only short-circuits for *pure-translation* matrices (drag); resize/rotate
|
||||||
|
matrices always pass through."
|
||||||
|
[prev new threshold]
|
||||||
|
(cond
|
||||||
|
(or (nil? prev) (nil? new)) true
|
||||||
|
(not= (count prev) (count new)) true
|
||||||
|
:else
|
||||||
|
(let [prev-map (into {} prev)]
|
||||||
|
(loop [pairs new]
|
||||||
|
(if-let [pair (first pairs)]
|
||||||
|
(let [id (nth pair 0)
|
||||||
|
^js m-new (nth pair 1)
|
||||||
|
^js m-prev (get prev-map id)]
|
||||||
|
(cond
|
||||||
|
(nil? m-prev) true
|
||||||
|
(or (not (== 1 (.-a m-new))) (not (== 0 (.-b m-new)))
|
||||||
|
(not (== 0 (.-c m-new))) (not (== 1 (.-d m-new)))
|
||||||
|
(not (== 1 (.-a m-prev))) (not (== 0 (.-b m-prev)))
|
||||||
|
(not (== 0 (.-c m-prev))) (not (== 1 (.-d m-prev))))
|
||||||
|
true
|
||||||
|
(or (> (js/Math.abs (- (.-e m-new) (.-e m-prev))) threshold)
|
||||||
|
(> (js/Math.abs (- (.-f m-new) (.-f m-prev))) threshold))
|
||||||
|
true
|
||||||
|
:else (recur (rest pairs))))
|
||||||
|
false)))))
|
||||||
|
|
||||||
(def workspace-wasm-modifiers
|
(def workspace-wasm-modifiers
|
||||||
(let [a (atom nil)]
|
(let [a (atom nil)
|
||||||
(rx/sub! ms/wasm-modifiers #(reset! a %))
|
last-emitted (volatile! nil)]
|
||||||
|
(rx/sub! ms/wasm-modifiers
|
||||||
|
(fn [val]
|
||||||
|
(when (wasm-modifiers-significant-change?
|
||||||
|
@last-emitted val wasm-modifier-jitter-threshold-px)
|
||||||
|
(vreset! last-emitted val)
|
||||||
|
(reset! a val))))
|
||||||
a))
|
a))
|
||||||
|
|
||||||
(def ^:private workspace-modifiers-with-objects
|
(def ^:private workspace-modifiers-with-objects
|
||||||
|
|||||||
@ -3270,6 +3270,23 @@ impl RenderState {
|
|||||||
.get_tiles_of(shape.id)
|
.get_tiles_of(shape.id)
|
||||||
.map_or(Vec::new(), |t| t.iter().copied().collect());
|
.map_or(Vec::new(), |t| t.iter().copied().collect());
|
||||||
|
|
||||||
|
// Drag fast path: when the shape's tile footprint is identical to
|
||||||
|
// last frame, the tile *content* still changed (the shape moved
|
||||||
|
// within those tiles), so callers must still invalidate the tile
|
||||||
|
// cache for that set — but the index `remove_shape_at` +
|
||||||
|
// `add_shape_at` shuffle is pure churn.
|
||||||
|
if self.options.is_interactive_transform() {
|
||||||
|
let new_count = ((rex - rsx + 1) * (rey - rsy + 1)) as usize;
|
||||||
|
if old_tiles.len() == new_count
|
||||||
|
&& old_tiles.iter().all(|t| {
|
||||||
|
let (x, y) = (t.x(), t.y());
|
||||||
|
x >= rsx && x <= rex && y >= rsy && y <= rey
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return old_tiles.into_iter().collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut result = HashSet::<tiles::Tile>::with_capacity(old_tiles.len());
|
let mut result = HashSet::<tiles::Tile>::with_capacity(old_tiles.len());
|
||||||
|
|
||||||
// First, remove the shape from all tiles where it was previously located
|
// First, remove the shape from all tiles where it was previously located
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user