mirror of
https://github.com/penpot/penpot.git
synced 2026-05-30 04:08:08 +00:00
🐛 Fix problem with position-data not present
* 🐛 Fix problem with position-data not present * 🐛 Async set-objects wait before calculate-position-data
This commit is contained in:
parent
eafd261ca6
commit
5a3a855b24
@ -9,6 +9,7 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.files.changes :as cpc]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.schema :as sm]
|
||||
@ -20,9 +21,11 @@
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.helpers :as dsh]
|
||||
[app.main.features :as features]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.router :as rt]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.util.globals :as ug]
|
||||
[beicon.v2.core :as rx]
|
||||
[potok.v2.core :as ptk]))
|
||||
@ -171,6 +174,88 @@
|
||||
(declare go-to-frame-by-index)
|
||||
(declare go-to-frame-auto)
|
||||
|
||||
;; Applies to the viewer the changes passed as parameters
|
||||
;; will not save the data but just modify the data localy
|
||||
(defn- apply-changes-viewer
|
||||
[changes]
|
||||
(ptk/reify ::apply-changes-viewer
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [file (-> (dm/get-in state [:viewer :file])
|
||||
(update :data cpc/process-changes changes false))
|
||||
|
||||
pages
|
||||
(->> (dm/get-in file [:data :pages])
|
||||
(map (fn [page-id]
|
||||
(let [data (get-in file [:data :pages-index page-id])]
|
||||
[page-id (assoc data
|
||||
:frames (ctt/get-viewer-frames (:objects data))
|
||||
:all-frames (ctt/get-viewer-frames (:objects data) {:all-frames? true}))])))
|
||||
(into {}))]
|
||||
|
||||
(-> state
|
||||
(assoc-in [:viewer :file] file)
|
||||
(assoc-in [:viewer :pages] pages))))))
|
||||
|
||||
(defn- generate-update-position-data-changes
|
||||
[shapes page-id]
|
||||
(reduce
|
||||
(fn [result shape]
|
||||
(conj result
|
||||
{:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:operations
|
||||
[{:type :set
|
||||
:attr :position-data
|
||||
:val (wasm.api/calculate-position-data shape)
|
||||
:ignore-touched true
|
||||
:ignore-geometry true}]}))
|
||||
[]
|
||||
shapes))
|
||||
|
||||
(defn update-page-position-data
|
||||
[file-id page-id]
|
||||
(ptk/reify ::update-page-position-data
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(if (features/active-feature? state "render-wasm/v1")
|
||||
(let [objects (dsh/lookup-page-objects state file-id page-id)
|
||||
|
||||
shapes
|
||||
(reduce-kv
|
||||
(fn [result _ shape]
|
||||
(cond-> result
|
||||
(and (cfh/text-shape? shape) (nil? (:position-data shape)))
|
||||
(conj shape)))
|
||||
[]
|
||||
objects)
|
||||
|
||||
;; Creates a stream from the async callback. This stream will only
|
||||
;; emit one single value after the objects have finished loading
|
||||
;; in the wasm memory.
|
||||
set-objects-stream
|
||||
(rx/create
|
||||
(fn [subs]
|
||||
(wasm.api/init-canvas-context (js/OffscreenCanvas. 0 0))
|
||||
(wasm.api/set-objects-callback shapes #(rx/push! subs :done))
|
||||
nil))]
|
||||
|
||||
(if (d/not-empty? shapes)
|
||||
(->> (rx/from @wasm.api/module)
|
||||
(rx/mapcat (constantly set-objects-stream))
|
||||
(rx/mapcat
|
||||
(fn []
|
||||
(let [changes (generate-update-position-data-changes shapes page-id)
|
||||
_ (wasm.api/clear-canvas)]
|
||||
(if (d/not-empty? changes)
|
||||
(rx/of (apply-changes-viewer changes))
|
||||
(rx/empty))))))
|
||||
(rx/empty)))
|
||||
|
||||
;; Render wasm disabled, we do nothing
|
||||
(rx/empty)))))
|
||||
|
||||
(defn bundle-fetched
|
||||
[{:keys [project file team share-links libraries users permissions thumbnails] :as bundle}]
|
||||
(let [pages (->> (dm/get-in file [:data :pages])
|
||||
@ -205,13 +290,17 @@
|
||||
(let [route (:route state)
|
||||
qparams (:query-params route)
|
||||
index (some-> (rt/get-query-param qparams :index) parse-long)
|
||||
frame-id (some-> (:frame-id qparams) uuid/parse)]
|
||||
frame-id (some-> (:frame-id qparams) uuid/parse)
|
||||
page-id (some-> (rt/get-query-param qparams :page-id) uuid/parse)
|
||||
file-id (some-> (rt/get-query-param qparams :file-id) uuid/parse)]
|
||||
|
||||
(rx/merge
|
||||
(rx/of (case (:zoom qparams)
|
||||
"fit" zoom-to-fit
|
||||
"fill" zoom-to-fill
|
||||
nil))
|
||||
(rx/of
|
||||
(update-page-position-data file-id page-id)
|
||||
(cond
|
||||
(some? frame-id) (go-to-frame frame-id)
|
||||
(some? index) (go-to-frame-by-index index)
|
||||
|
||||
@ -204,36 +204,40 @@
|
||||
(rx/take-until stopper-s))))))
|
||||
|
||||
|
||||
(defn check-file-position-data
|
||||
[file-id]
|
||||
(ptk/reify ::fix-position-data
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [file (dsh/lookup-file state file-id)
|
||||
changes
|
||||
(->> file :data :pages
|
||||
(mapcat
|
||||
(fn [page-id]
|
||||
(->> (dsh/lookup-page-objects state file-id page-id)
|
||||
(vals)
|
||||
(filter cfh/text-shape?)
|
||||
(filter #(nil? (:position-data %)))
|
||||
(map (fn [shape]
|
||||
{:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:operations
|
||||
[{:type :set
|
||||
:attr :position-data
|
||||
:val (wasm.api/calculate-position-data shape)
|
||||
:ignore-touched true
|
||||
:ignore-geometry true}]})))))
|
||||
(into []))]
|
||||
(rx/of (dch/commit-changes
|
||||
{:redo-changes changes :undo-changes []
|
||||
:save-undo? false
|
||||
:origin it
|
||||
:tags #{:position-data}}))))))
|
||||
(defn update-page-position-data
|
||||
([]
|
||||
(update-page-position-data nil nil))
|
||||
([file-id page-id]
|
||||
(ptk/reify ::update-page-position-data
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [file-id (or file-id (:current-file-id state))
|
||||
page-id (or page-id (:current-page-id state))
|
||||
changes
|
||||
(reduce-kv
|
||||
(fn [result _ shape]
|
||||
(if (and (cfh/text-shape? shape)
|
||||
(nil? (:position-data shape)))
|
||||
(conj result
|
||||
{:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:operations
|
||||
[{:type :set
|
||||
:attr :position-data
|
||||
:val (wasm.api/calculate-position-data shape)
|
||||
:ignore-touched true
|
||||
:ignore-geometry true}]})
|
||||
result))
|
||||
[]
|
||||
(dsh/lookup-page-objects state file-id page-id))]
|
||||
(if (d/not-empty? changes)
|
||||
(rx/of (dch/commit-changes
|
||||
{:redo-changes changes :undo-changes []
|
||||
:save-undo? false
|
||||
:origin it
|
||||
:tags #{:position-data}}))
|
||||
(rx/empty)))))))
|
||||
|
||||
(defn- workspace-initialized
|
||||
[file-id]
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.modal :as modal]
|
||||
;; [app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.transforms :as dwt]
|
||||
[app.main.data.workspace.variants :as dwv]
|
||||
[app.main.features :as features]
|
||||
@ -459,9 +459,9 @@
|
||||
;; is set.
|
||||
(wasm.api/initialize-viewport base-objects zoom vbox
|
||||
:background background
|
||||
;; :on-shapes-ready
|
||||
;; (st/emit! (dw/check-file-position-data file-id))
|
||||
)
|
||||
:on-shapes-ready
|
||||
(fn []
|
||||
(st/emit! (dw/update-page-position-data))))
|
||||
(reset! initialized? true))
|
||||
|
||||
(when (and (some? vern) (not= vern (mf/ref-val last-vern-ref)))
|
||||
|
||||
@ -438,6 +438,19 @@
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)))))
|
||||
|
||||
(defn has-shape
|
||||
[id]
|
||||
(when wasm/context-initialized?
|
||||
(let [buffer (uuid/get-u32 id)
|
||||
|
||||
result
|
||||
(h/call wasm/internal-module "_has_shape"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3))]
|
||||
(= result 1))))
|
||||
|
||||
(defn set-shape-text-content
|
||||
"This function sets shape text content and returns a stream that loads the needed fonts asynchronously"
|
||||
[shape-id content]
|
||||
@ -1404,6 +1417,53 @@
|
||||
noop-fn)))))))]
|
||||
(process-next-chunk 0 [] []))))))
|
||||
|
||||
|
||||
;; This is a version of process-pending that doesn't have sideffects
|
||||
;; with like request render or update layout.
|
||||
(defn- process-pending-no-sideffects
|
||||
[thumbnails full on-complete]
|
||||
(let [pending-thumbnails
|
||||
(d/index-by :key :callback thumbnails)
|
||||
|
||||
pending-full
|
||||
(d/index-by :key :callback full)]
|
||||
|
||||
(if (or (seq pending-thumbnails) (seq pending-full))
|
||||
(->> (rx/concat
|
||||
(->> (rx/from (vals pending-thumbnails))
|
||||
(rx/merge-map (fn [callback] (if (fn? callback) (callback) (rx/empty))))
|
||||
(rx/reduce conj [])
|
||||
(rx/catch #(rx/empty)))
|
||||
(->> (rx/from (vals pending-full))
|
||||
(rx/mapcat (fn [callback] (if (fn? callback) (callback) (rx/empty))))
|
||||
(rx/reduce conj [])
|
||||
(rx/catch #(rx/empty))))
|
||||
(rx/subs!
|
||||
noop-fn
|
||||
noop-fn
|
||||
(fn []
|
||||
(when (fn? on-complete) (on-complete)))))
|
||||
;; No pending images — complete immediately.
|
||||
(when on-complete (on-complete)))))
|
||||
|
||||
(defn set-objects-callback
|
||||
"Sets the shapes and when the async operations are done calls the callback. Won't
|
||||
interact with the rendering pipeline, this call is only to set the model (used currently
|
||||
in the viewer)."
|
||||
[shapes set-objects-cb]
|
||||
(let [total-shapes (count shapes)
|
||||
{:keys [thumbnails full]}
|
||||
(loop [index 0 thumbnails-acc (transient []) full-acc (transient [])]
|
||||
(if (< index total-shapes)
|
||||
(let [shape (nth shapes index)
|
||||
{:keys [thumbnails full]} (set-object shape)]
|
||||
(recur (inc index)
|
||||
(reduce conj! thumbnails-acc thumbnails)
|
||||
(reduce conj! full-acc full)))
|
||||
{:thumbnails (persistent! thumbnails-acc) :full (persistent! full-acc)}))]
|
||||
|
||||
(process-pending-no-sideffects thumbnails full set-objects-cb)))
|
||||
|
||||
(defn- set-objects-sync
|
||||
"Synchronously process all shapes (for small shape counts)."
|
||||
[shapes render-callback on-shapes-ready]
|
||||
|
||||
@ -407,6 +407,15 @@ pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn has_shape(a: u32, b: u32, c: u32, d: u32) -> Result<bool> {
|
||||
with_state!(state, {
|
||||
let id = uuid_from_u32_quartet(a, b, c, d);
|
||||
return Ok(state.has_shape(id));
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[wasm_error]
|
||||
pub extern "C" fn touch_shape(a: u32, b: u32, c: u32, d: u32) -> Result<()> {
|
||||
|
||||
@ -119,6 +119,10 @@ impl State {
|
||||
self.current_id = Some(id);
|
||||
}
|
||||
|
||||
pub fn has_shape(&mut self, id: Uuid) -> bool {
|
||||
self.shapes.has(&id)
|
||||
}
|
||||
|
||||
pub fn delete_shape_children(&mut self, parent_id: Uuid, id: Uuid) {
|
||||
let render_state = get_render_state();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user