Merge pull request #3590 from penpot/niwinz-develop-experiments-2

🐛 & 
This commit is contained in:
Alejandro 2023-09-05 11:12:55 +02:00 committed by GitHub
commit a4ed9e57fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 380 additions and 335 deletions

View file

@ -146,10 +146,6 @@
(transient-concat c1 more) (transient-concat c1 more)
(transient-concat [] (cons c1 more))))) (transient-concat [] (cons c1 more)))))
(defn preconj
[coll elem]
(into [elem] coll))
(defn enumerate (defn enumerate
([items] (enumerate items 0)) ([items] (enumerate items 0))
([items start] ([items start]

View file

@ -275,21 +275,19 @@
[a b] [a b]
(mth/almost-zero? (- a b))) (mth/almost-zero? (- a b)))
;; FIXME: performance
(defn overlaps-rects? (defn overlaps-rects?
"Check for two rects to overlap. Rects won't overlap only if "Check for two rects to overlap. Rects won't overlap only if
one of them is fully to the left or the top" one of them is fully to the left or the top"
[rect-a rect-b] [rect-a rect-b]
(let [x1a (dm/get-prop rect-a :x)
y1a (dm/get-prop rect-a :y)
x2a (+ x1a (dm/get-prop rect-a :width))
y2a (+ y1a (dm/get-prop rect-a :height))
(let [x1a (:x rect-a) x1b (dm/get-prop rect-b :x)
y1a (:y rect-a) y1b (dm/get-prop rect-b :y)
x2a (+ (:x rect-a) (:width rect-a)) x2b (+ x1b (dm/get-prop rect-b :width))
y2a (+ (:y rect-a) (:height rect-a)) y2b (+ y1b (dm/get-prop rect-b :height))]
x1b (:x rect-b)
y1b (:y rect-b)
x2b (+ (:x rect-b) (:width rect-b))
y2b (+ (:y rect-b) (:height rect-b))]
(and (or (> x2a x1b) (s= x2a x1b)) (and (or (> x2a x1b) (s= x2a x1b))
(or (>= x2b x1a) (s= x2b x1a)) (or (>= x2b x1a) (s= x2b x1a))

View file

@ -305,30 +305,27 @@
(defn overlaps? (defn overlaps?
"General case to check for overlapping between shapes and a rectangle" "General case to check for overlapping between shapes and a rectangle"
[shape rect] [shape rect]
(let [stroke-width (/ (or (:stroke-width shape) 0) 2) (let [swidth (/ (or (:stroke-width shape) 0) 2)
rect (-> rect rect (-> rect
(update :x - stroke-width) (update :x - swidth)
(update :y - stroke-width) (update :y - swidth)
(update :width + (* 2 stroke-width)) (update :width + (* 2 swidth))
(update :height + (* 2 stroke-width)))] (update :height + (* 2 swidth)))]
(or (not shape) (or (not shape)
(let [path? (= :path (:type shape))
circle? (= :circle (:type shape))
text? (= :text (:type shape))]
(cond (cond
path? (cph/path-shape? shape)
(and (overlaps-rect-points? rect (:points shape)) (and (overlaps-rect-points? rect (:points shape))
(overlaps-path? shape rect)) (overlaps-path? shape rect))
circle? (cph/circle-shape? shape)
(and (overlaps-rect-points? rect (:points shape)) (and (overlaps-rect-points? rect (:points shape))
(overlaps-ellipse? shape rect)) (overlaps-ellipse? shape rect))
text? (cph/text-shape? shape)
(overlaps-text? shape rect) (overlaps-text? shape rect)
:else :else
(overlaps-rect-points? rect (:points shape))))))) (overlaps-rect-points? rect (:points shape))))))
(defn has-point-rect? (defn has-point-rect?
[rect point] [rect point]

View file

@ -16,6 +16,7 @@
[app.common.math :as mth] [app.common.math :as mth]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.schema :as sm]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
@ -23,6 +24,18 @@
;; Auxiliary functions to help create a set of changes (undo + redo) ;; Auxiliary functions to help create a set of changes (undo + redo)
(def schema:changes
[:map
[:redo-changes vector?]
[:undo-changes seq?]
[:origin {:optional true} any?]
[:save-undo? {:optional true} boolean?]
[:stack-undo? {:optional true} boolean?]
[:undo-group {:optional true} any?]])
(def valid-changes?
(sm/pred-fn schema:changes))
(defn empty-changes (defn empty-changes
([origin page-id] ([origin page-id]
(let [changes (empty-changes origin)] (let [changes (empty-changes origin)]
@ -31,7 +44,7 @@
([origin] ([origin]
{:redo-changes [] {:redo-changes []
:undo-changes [] :undo-changes '()
:origin origin})) :origin origin}))
(defn set-save-undo? (defn set-save-undo?
@ -87,34 +100,45 @@
(defn concat-changes (defn concat-changes
[changes1 changes2] [changes1 changes2]
{:redo-changes (d/concat-vec (:redo-changes changes1) (:redo-changes changes2)) {:redo-changes (d/concat-vec (:redo-changes changes1)
:undo-changes (d/concat-vec (:undo-changes changes1) (:undo-changes changes2)) (:redo-changes changes2))
:undo-changes (concat (:undo-changes changes1)
(:undo-changes changes2))
:origin (:origin changes1) :origin (:origin changes1)
:undo-group (:undo-group changes1) :undo-group (:undo-group changes1)
:tags (:tags changes1)}) :tags (:tags changes1)})
; TODO: remove this when not needed ; TODO: remove this when not needed
(defn- assert-page-id (defn- assert-page-id!
[changes] [changes]
(assert (contains? (meta changes) ::page-id) "Give a page-id or call (with-page) before using this function")) (dm/assert!
"Give a page-id or call (with-page) before using this function"
(contains? (meta changes) ::page-id)))
(defn- assert-container-id (defn- assert-container-id!
[changes] [changes]
(assert (or (contains? (meta changes) ::page-id) (dm/assert!
(contains? (meta changes) ::component-id)) "Give a page-id or call (with-container) before using this function"
"Give a page-id or call (with-container) before using this function")) (or (contains? (meta changes) ::page-id)
(contains? (meta changes) ::component-id))))
(defn- assert-page (defn- assert-page!
[changes] [changes]
(assert (contains? (meta changes) ::page) "Call (with-page) before using this function")) (dm/assert!
"Call (with-page) before using this function"
(contains? (meta changes) ::page)))
(defn- assert-objects (defn- assert-objects!
[changes] [changes]
(assert (contains? (meta changes) ::file-data) "Call (with-objects) before using this function")) (dm/assert!
"Call (with-objects) before using this function"
(contains? (meta changes) ::file-data)))
(defn- assert-library (defn- assert-library!
[changes] [changes]
(assert (contains? (meta changes) ::library-data) "Call (with-library-data) before using this function")) (dm/assert!
"Call (with-library-data) before using this function"
(contains? (meta changes) ::library-data)))
(defn- lookup-objects (defn- lookup-objects
[changes] [changes]
@ -123,6 +147,10 @@
(defn- apply-changes-local (defn- apply-changes-local
[changes] [changes]
(dm/assert!
"expected valid changes"
(valid-changes? changes))
(if-let [file-data (::file-data (meta changes))] (if-let [file-data (::file-data (meta changes))]
(let [index (::applied-changes-count (meta changes)) (let [index (::applied-changes-count (meta changes))
redo-changes (:redo-changes changes) redo-changes (:redo-changes changes)
@ -143,40 +171,40 @@
[changes id name] [changes id name]
(-> changes (-> changes
(update :redo-changes conj {:type :add-page :id id :name name}) (update :redo-changes conj {:type :add-page :id id :name name})
(update :undo-changes d/preconj {:type :del-page :id id}) (update :undo-changes conj {:type :del-page :id id})
(apply-changes-local))) (apply-changes-local)))
(defn add-page (defn add-page
[changes id page] [changes id page]
(-> changes (-> changes
(update :redo-changes conj {:type :add-page :id id :page page}) (update :redo-changes conj {:type :add-page :id id :page page})
(update :undo-changes d/preconj {:type :del-page :id id}) (update :undo-changes conj {:type :del-page :id id})
(apply-changes-local))) (apply-changes-local)))
(defn mod-page (defn mod-page
[changes page new-name] [changes page new-name]
(-> changes (-> changes
(update :redo-changes conj {:type :mod-page :id (:id page) :name new-name}) (update :redo-changes conj {:type :mod-page :id (:id page) :name new-name})
(update :undo-changes d/preconj {:type :mod-page :id (:id page) :name (:name page)}) (update :undo-changes conj {:type :mod-page :id (:id page) :name (:name page)})
(apply-changes-local))) (apply-changes-local)))
(defn del-page (defn del-page
[changes page] [changes page]
(-> changes (-> changes
(update :redo-changes conj {:type :del-page :id (:id page)}) (update :redo-changes conj {:type :del-page :id (:id page)})
(update :undo-changes d/preconj {:type :add-page :id (:id page) :page page}) (update :undo-changes conj {:type :add-page :id (:id page) :page page})
(apply-changes-local))) (apply-changes-local)))
(defn move-page (defn move-page
[changes page-id index prev-index] [changes page-id index prev-index]
(-> changes (-> changes
(update :redo-changes conj {:type :mov-page :id page-id :index index}) (update :redo-changes conj {:type :mov-page :id page-id :index index})
(update :undo-changes d/preconj {:type :mov-page :id page-id :index prev-index}) (update :undo-changes conj {:type :mov-page :id page-id :index prev-index})
(apply-changes-local))) (apply-changes-local)))
(defn set-page-option (defn set-page-option
[changes option-key option-val] [changes option-key option-val]
(assert-page changes) (assert-page! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
page (::page (meta changes)) page (::page (meta changes))
old-val (get-in page [:options option-key])] old-val (get-in page [:options option-key])]
@ -186,7 +214,7 @@
:page-id page-id :page-id page-id
:option option-key :option option-key
:value option-val}) :value option-val})
(update :undo-changes d/preconj {:type :set-option (update :undo-changes conj {:type :set-option
:page-id page-id :page-id page-id
:option option-key :option option-key
:value old-val}) :value old-val})
@ -194,7 +222,7 @@
(defn update-page-option (defn update-page-option
[changes option-key update-fn & args] [changes option-key update-fn & args]
(assert-page changes) (assert-page! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
page (::page (meta changes)) page (::page (meta changes))
old-val (get-in page [:options option-key]) old-val (get-in page [:options option-key])
@ -205,7 +233,7 @@
:page-id page-id :page-id page-id
:option option-key :option option-key
:value new-val}) :value new-val})
(update :undo-changes d/preconj {:type :set-option (update :undo-changes conj {:type :set-option
:page-id page-id :page-id page-id
:option option-key :option option-key
:value old-val}) :value old-val})
@ -221,8 +249,8 @@
;; FIXME: add shape validation ;; FIXME: add shape validation
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [obj (cond-> obj (let [obj (cond-> obj
(not= index ::undefined) (not= index ::undefined)
(assoc ::index index)) (assoc ::index index))
@ -256,8 +284,8 @@
(update :redo-changes conj add-change) (update :redo-changes conj add-change)
(cond-> (cond->
(and (ctk/in-component-copy? parent) (not ignore-touched)) (and (ctk/in-component-copy? parent) (not ignore-touched))
(update :undo-changes d/preconj restore-touched-change)) (update :undo-changes conj restore-touched-change))
(update :undo-changes d/preconj del-change) (update :undo-changes conj del-change)
(apply-changes-local))))) (apply-changes-local)))))
(defn add-objects (defn add-objects
@ -274,8 +302,8 @@
(change-parent changes parent-id shapes nil)) (change-parent changes parent-id shapes nil))
([changes parent-id shapes index] ([changes parent-id shapes index]
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [objects (lookup-objects changes) (let [objects (lookup-objects changes)
parent (get objects parent-id) parent (get objects parent-id)
@ -289,10 +317,9 @@
(assoc :index index)) (assoc :index index))
mk-undo-change mk-undo-change
(fn [change-set shape] (fn [undo-changes shape]
(let [prev-sibling (cph/get-prev-sibling objects (:id shape))] (let [prev-sibling (cph/get-prev-sibling objects (:id shape))]
(d/preconj (conj undo-changes
change-set
{:type :mov-objects {:type :mov-objects
:page-id (::page-id (meta changes)) :page-id (::page-id (meta changes))
:parent-id (:parent-id shape) :parent-id (:parent-id shape)
@ -311,7 +338,7 @@
(update :redo-changes conj set-parent-change) (update :redo-changes conj set-parent-change)
(cond-> (cond->
(ctk/in-component-copy? parent) (ctk/in-component-copy? parent)
(update :undo-changes d/preconj restore-touched-change)) (update :undo-changes conj restore-touched-change))
(update :undo-changes #(reduce mk-undo-change % shapes)) (update :undo-changes #(reduce mk-undo-change % shapes))
(apply-changes-local))))) (apply-changes-local)))))
@ -336,24 +363,28 @@
([changes ids update-fn {:keys [attrs ignore-geometry? ignore-touched] ([changes ids update-fn {:keys [attrs ignore-geometry? ignore-touched]
:or {ignore-geometry? false ignore-touched false}}] :or {ignore-geometry? false ignore-touched false}}]
(assert-container-id changes) (assert-container-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
component-id (::component-id (meta changes)) component-id (::component-id (meta changes))
objects (lookup-objects changes) objects (lookup-objects changes)
generate-operation generate-operations
(fn [operations attr old new ignore-geometry?] (fn [attrs old new]
(loop [rops []
uops '()
attrs (seq attrs)]
(if-let [attr (first attrs)]
(let [old-val (get old attr) (let [old-val (get old attr)
new-val (get new attr)] new-val (get new attr)]
(if (= old-val new-val)
operations (recur (conj rops {:type :set :attr attr :val new-val
(-> operations
(update :rops conj {:type :set :attr attr :val new-val
:ignore-geometry ignore-geometry? :ignore-geometry ignore-geometry?
:ignore-touched ignore-touched}) :ignore-touched ignore-touched})
(update :uops d/preconj {:type :set :attr attr :val old-val (conj uops {:type :set :attr attr :val old-val
:ignore-touched true}))))) :ignore-touched true})
(rest attrs)))
[rops uops])))
update-shape update-shape
(fn [changes id] (fn [changes id]
@ -361,20 +392,14 @@
new-obj (update-fn old-obj)] new-obj (update-fn old-obj)]
(if (= old-obj new-obj) (if (= old-obj new-obj)
changes changes
(let [attrs (or attrs (d/concat-set (keys old-obj) (keys new-obj))) (let [[rops uops] (-> (or attrs (d/concat-set (keys old-obj) (keys new-obj)))
(generate-operations old-obj new-obj))
{rops :rops uops :uops}
(reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
{:rops [] :uops []}
attrs)
uops (cond-> uops uops (cond-> uops
(seq uops) (seq uops)
(d/preconj {:type :set-touched :touched (:touched old-obj)})) (conj {:type :set-touched :touched (:touched old-obj)}))
change (cond-> {:type :mod-obj
:id id}
change (cond-> {:type :mod-obj :id id}
(some? page-id) (some? page-id)
(assoc :page-id page-id) (assoc :page-id page-id)
@ -386,7 +411,7 @@
(update :redo-changes conj (assoc change :operations rops)) (update :redo-changes conj (assoc change :operations rops))
(seq uops) (seq uops)
(update :undo-changes d/preconj (assoc change :operations uops)))))))] (update :undo-changes conj (assoc change :operations (vec uops))))))))]
(-> (reduce update-shape changes ids) (-> (reduce update-shape changes ids)
(apply-changes-local))))) (apply-changes-local)))))
@ -394,8 +419,8 @@
(defn remove-objects (defn remove-objects
([changes ids] (remove-objects changes ids nil)) ([changes ids] (remove-objects changes ids nil))
([changes ids {:keys [ignore-touched] :or {ignore-touched false}}] ([changes ids {:keys [ignore-touched] :or {ignore-touched false}}]
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
objects (lookup-objects changes) objects (lookup-objects changes)
@ -410,7 +435,7 @@
add-undo-change-shape add-undo-change-shape
(fn [change-set id] (fn [change-set id]
(let [shape (get objects id)] (let [shape (get objects id)]
(d/preconj (conj
change-set change-set
{:type :add-obj {:type :add-obj
:id id :id id
@ -426,7 +451,7 @@
(fn [change-set id] (fn [change-set id]
(let [shape (get objects id) (let [shape (get objects id)
prev-sibling (cph/get-prev-sibling objects (:id shape))] prev-sibling (cph/get-prev-sibling objects (:id shape))]
(d/preconj (conj
change-set change-set
{:type :mov-objects {:type :mov-objects
:page-id page-id :page-id page-id
@ -445,8 +470,8 @@
(defn resize-parents (defn resize-parents
[changes ids] [changes ids]
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
objects (lookup-objects changes) objects (lookup-objects changes)
@ -481,7 +506,7 @@
operations operations
(-> operations (-> operations
(update :rops conj {:type :set :attr attr :val new-val :ignore-touched true}) (update :rops conj {:type :set :attr attr :val new-val :ignore-touched true})
(update :uops d/preconj {:type :set :attr attr :val old-val :ignore-touched true}))))) (update :uops conj {:type :set :attr attr :val old-val :ignore-touched true})))))
resize-parent resize-parent
(fn [changes parent] (fn [changes parent]
@ -511,7 +536,7 @@
(if (seq rops) (if (seq rops)
(-> changes (-> changes
(update :redo-changes conj (assoc change :operations rops)) (update :redo-changes conj (assoc change :operations rops))
(update :undo-changes d/preconj (assoc change :operations uops)) (update :undo-changes conj (assoc change :operations uops))
(apply-changes-local)) (apply-changes-local))
changes)) changes))
changes)))] changes)))]
@ -530,89 +555,89 @@
[changes color] [changes color]
(-> changes (-> changes
(update :redo-changes conj {:type :add-color :color color}) (update :redo-changes conj {:type :add-color :color color})
(update :undo-changes d/preconj {:type :del-color :id (:id color)}) (update :undo-changes conj {:type :del-color :id (:id color)})
(apply-changes-local))) (apply-changes-local)))
(defn update-color (defn update-color
[changes color] [changes color]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-color (get-in library-data [:colors (:id color)])] prev-color (get-in library-data [:colors (:id color)])]
(-> changes (-> changes
(update :redo-changes conj {:type :mod-color :color color}) (update :redo-changes conj {:type :mod-color :color color})
(update :undo-changes d/preconj {:type :mod-color :color prev-color}) (update :undo-changes conj {:type :mod-color :color prev-color})
(apply-changes-local)))) (apply-changes-local))))
(defn delete-color (defn delete-color
[changes color-id] [changes color-id]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-color (get-in library-data [:colors color-id])] prev-color (get-in library-data [:colors color-id])]
(-> changes (-> changes
(update :redo-changes conj {:type :del-color :id color-id}) (update :redo-changes conj {:type :del-color :id color-id})
(update :undo-changes d/preconj {:type :add-color :color prev-color}) (update :undo-changes conj {:type :add-color :color prev-color})
(apply-changes-local)))) (apply-changes-local))))
(defn add-media (defn add-media
[changes object] [changes object]
(-> changes (-> changes
(update :redo-changes conj {:type :add-media :object object}) (update :redo-changes conj {:type :add-media :object object})
(update :undo-changes d/preconj {:type :del-media :id (:id object)}) (update :undo-changes conj {:type :del-media :id (:id object)})
(apply-changes-local))) (apply-changes-local)))
(defn update-media (defn update-media
[changes object] [changes object]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-object (get-in library-data [:media (:id object)])] prev-object (get-in library-data [:media (:id object)])]
(-> changes (-> changes
(update :redo-changes conj {:type :mod-media :object object}) (update :redo-changes conj {:type :mod-media :object object})
(update :undo-changes d/preconj {:type :mod-media :object prev-object}) (update :undo-changes conj {:type :mod-media :object prev-object})
(apply-changes-local)))) (apply-changes-local))))
(defn delete-media (defn delete-media
[changes id] [changes id]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-object (get-in library-data [:media id])] prev-object (get-in library-data [:media id])]
(-> changes (-> changes
(update :redo-changes conj {:type :del-media :id id}) (update :redo-changes conj {:type :del-media :id id})
(update :undo-changes d/preconj {:type :add-media :object prev-object}) (update :undo-changes conj {:type :add-media :object prev-object})
(apply-changes-local)))) (apply-changes-local))))
(defn add-typography (defn add-typography
[changes typography] [changes typography]
(-> changes (-> changes
(update :redo-changes conj {:type :add-typography :typography typography}) (update :redo-changes conj {:type :add-typography :typography typography})
(update :undo-changes d/preconj {:type :del-typography :id (:id typography)}) (update :undo-changes conj {:type :del-typography :id (:id typography)})
(apply-changes-local))) (apply-changes-local)))
(defn update-typography (defn update-typography
[changes typography] [changes typography]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-typography (get-in library-data [:typographies (:id typography)])] prev-typography (get-in library-data [:typographies (:id typography)])]
(-> changes (-> changes
(update :redo-changes conj {:type :mod-typography :typography typography}) (update :redo-changes conj {:type :mod-typography :typography typography})
(update :undo-changes d/preconj {:type :mod-typography :typography prev-typography}) (update :undo-changes conj {:type :mod-typography :typography prev-typography})
(apply-changes-local)))) (apply-changes-local))))
(defn delete-typography (defn delete-typography
[changes typography-id] [changes typography-id]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-typography (get-in library-data [:typographies typography-id])] prev-typography (get-in library-data [:typographies typography-id])]
(-> changes (-> changes
(update :redo-changes conj {:type :del-typography :id typography-id}) (update :redo-changes conj {:type :del-typography :id typography-id})
(update :undo-changes d/preconj {:type :add-typography :typography prev-typography}) (update :undo-changes conj {:type :add-typography :typography prev-typography})
(apply-changes-local)))) (apply-changes-local))))
(defn add-component (defn add-component
([changes id path name new-shapes updated-shapes main-instance-id main-instance-page] ([changes id path name new-shapes updated-shapes main-instance-id main-instance-page]
(add-component changes id path name new-shapes updated-shapes main-instance-id main-instance-page nil)) (add-component changes id path name new-shapes updated-shapes main-instance-id main-instance-page nil))
([changes id path name new-shapes updated-shapes main-instance-id main-instance-page annotation] ([changes id path name new-shapes updated-shapes main-instance-id main-instance-page annotation]
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
objects (lookup-objects changes) objects (lookup-objects changes)
lookupf (d/getf objects) lookupf (d/getf objects)
@ -656,7 +681,7 @@
(update :undo-changes (update :undo-changes
(fn [undo-changes] (fn [undo-changes]
(-> undo-changes (-> undo-changes
(d/preconj {:type :del-component (conj {:type :del-component
:id id :id id
:skip-undelete? true}) :skip-undelete? true})
(into (comp (map :id) (into (comp (map :id)
@ -667,7 +692,7 @@
(defn update-component (defn update-component
[changes id update-fn] [changes id update-fn]
(assert-library changes) (assert-library! changes)
(let [library-data (::library-data (meta changes)) (let [library-data (::library-data (meta changes))
prev-component (get-in library-data [:components id]) prev-component (get-in library-data [:components id])
new-component (update-fn prev-component)] new-component (update-fn prev-component)]
@ -679,7 +704,7 @@
:path (:path new-component) :path (:path new-component)
:annotation (:annotation new-component) :annotation (:annotation new-component)
:objects (:objects new-component)}) ;; this won't exist in components-v2 :objects (:objects new-component)}) ;; this won't exist in components-v2
(update :undo-changes d/preconj {:type :mod-component (update :undo-changes conj {:type :mod-component
:id id :id id
:name (:name prev-component) :name (:name prev-component)
:path (:path prev-component) :path (:path prev-component)
@ -689,23 +714,23 @@
(defn delete-component (defn delete-component
[changes id] [changes id]
(assert-library changes) (assert-library! changes)
(-> changes (-> changes
(update :redo-changes conj {:type :del-component (update :redo-changes conj {:type :del-component
:id id}) :id id})
(update :undo-changes d/preconj {:type :restore-component (update :undo-changes conj {:type :restore-component
:id id}))) :id id})))
(defn restore-component (defn restore-component
([changes id] ([changes id]
(restore-component changes id nil)) (restore-component changes id nil))
([changes id page-id] ([changes id page-id]
(assert-library changes) (assert-library! changes)
(-> changes (-> changes
(update :redo-changes conj {:type :restore-component (update :redo-changes conj {:type :restore-component
:id id :id id
:page-id page-id}) :page-id page-id})
(update :undo-changes d/preconj {:type :del-component (update :undo-changes conj {:type :del-component
:id id})))) :id id}))))
(defn ignore-remote (defn ignore-remote
@ -720,8 +745,8 @@
(defn reorder-grid-children (defn reorder-grid-children
[changes ids] [changes ids]
(assert-page-id changes) (assert-page-id! changes)
(assert-objects changes) (assert-objects! changes)
(let [page-id (::page-id (meta changes)) (let [page-id (::page-id (meta changes))
objects (lookup-objects changes) objects (lookup-objects changes)
@ -746,7 +771,7 @@
:shapes old-shapes}] :shapes old-shapes}]
(-> changes (-> changes
(update :redo-changes conj redo-change) (update :redo-changes conj redo-change)
(update :undo-changes d/preconj undo-change) (update :undo-changes conj undo-change)
(apply-changes-local)))) (apply-changes-local))))
changes changes

View file

@ -180,7 +180,9 @@
:or {save-undo? true stack-undo? false tags #{} undo-group (uuid/next)}}] :or {save-undo? true stack-undo? false tags #{} undo-group (uuid/next)}}]
(let [error (volatile! nil) (let [error (volatile! nil)
page-id (:current-page-id @st/state) page-id (:current-page-id @st/state)
frames (changed-frames redo-changes (wsh/lookup-page-objects @st/state))] frames (changed-frames redo-changes (wsh/lookup-page-objects @st/state))
undo-changes (vec undo-changes)
redo-changes (vec redo-changes)]
(ptk/reify ::commit-changes (ptk/reify ::commit-changes
cljs.core/IDeref cljs.core/IDeref
(-deref [_] (-deref [_]

View file

@ -413,7 +413,7 @@
:operations [{:type :set :operations [{:type :set
:attr :content :attr :content
:val new-content}]})) :val new-content}]}))
(update :undo-changes d/preconj (make-change (update :undo-changes conj (make-change
container container
{:type :mod-obj {:type :mod-obj
:id (:id shape) :id (:id shape)
@ -573,8 +573,8 @@
initial-root? initial-root?
redirect-shaperef redirect-shaperef
components-v2) components-v2)
; If the component is not found, because the master component has been ;; If the component is not found, because the master component has been
; deleted or the library unlinked, do nothing in v2 or detach in v1. ;; deleted or the library unlinked, do nothing in v2 or detach in v1.
(if components-v2 (if components-v2
changes changes
(generate-detach-instance changes container shape-id)))) (generate-detach-instance changes container shape-id))))
@ -827,10 +827,10 @@
(-> changes (-> changes
(update :redo-changes (partial mapv check-local)) (update :redo-changes (partial mapv check-local))
(update :undo-changes (partial mapv check-local)))))) (update :undo-changes (partial map check-local))))))
; ---- Operation generation helpers ---- ;; ---- Operation generation helpers ----
(defn- compare-children (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?]
@ -931,7 +931,7 @@
(assoc :frame-id (:frame-id shape'))))))) (assoc :frame-id (:frame-id shape')))))))
del-obj-change (fn [changes shape'] del-obj-change (fn [changes shape']
(update changes :undo-changes d/preconj (update changes :undo-changes conj
(make-change (make-change
container container
{:type :del-obj {:type :del-obj
@ -1014,7 +1014,7 @@
:val (:touched shape')}]})) :val (:touched shape')}]}))
del-obj-change (fn [changes shape'] del-obj-change (fn [changes shape']
(update changes :undo-changes d/preconj (update changes :undo-changes conj
{:type :del-obj {:type :del-obj
:id (:id shape') :id (:id shape')
:page-id (:id page) :page-id (:id page)
@ -1050,7 +1050,7 @@
add-undo-change (fn [changes id] add-undo-change (fn [changes id]
(let [shape' (get objects id)] (let [shape' (get objects id)]
(update changes :undo-changes d/preconj (update changes :undo-changes conj
(make-change (make-change
container container
(as-> {:type :add-obj (as-> {:type :add-obj
@ -1097,7 +1097,7 @@
:shapes [(:id shape)] :shapes [(:id shape)]
:index index-after :index index-after
:ignore-touched true})) :ignore-touched true}))
(update :undo-changes d/preconj (make-change (update :undo-changes conj (make-change
container container
{:type :mov-objects {:type :mov-objects
:parent-id (:parent-id shape) :parent-id (:parent-id shape)
@ -1138,7 +1138,7 @@
:operations :operations
[{:type :set-touched [{:type :set-touched
:touched new-touched}]})) :touched new-touched}]}))
(update :undo-changes d/preconj (make-change (update :undo-changes conj (make-change
container container
{:type :mod-obj {:type :mod-obj
:id (:id dest-shape) :id (:id dest-shape)
@ -1163,7 +1163,7 @@
:operations :operations
[{:type :set-remote-synced [{:type :set-remote-synced
:remote-synced remote-synced?}]})) :remote-synced remote-synced?}]}))
(update :undo-changes d/preconj (make-change (update :undo-changes conj (make-change
container container
{:type :mod-obj {:type :mod-obj
:id (:id shape) :id (:id shape)
@ -1185,19 +1185,19 @@
(if (cph/page? container) "[P] " "[C] ") (if (cph/page? container) "[P] " "[C] ")
(:name dest-shape))) (:name dest-shape)))
(let [; To synchronize geometry attributes we need to make a prior (let [;; To synchronize geometry attributes we need to make a prior
; operation, because coordinates are absolute, but we need to ;; operation, because coordinates are absolute, but we need to
; sync only the position relative to the origin of the component. ;; sync only the position relative to the origin of the component.
; We solve this by moving the origin shape so it is aligned with ;; We solve this by moving the origin shape so it is aligned with
; the dest root before syncing. ;; the dest root before syncing.
; In case of subinstances, the comparison is always done with the ;; In case of subinstances, the comparison is always done with the
; near component, because this is that we are syncing with. ;; near component, because this is that we are syncing with.
origin-shape (reposition-shape origin-shape origin-root dest-root) origin-shape (reposition-shape origin-shape origin-root dest-root)
touched (get dest-shape :touched #{})] touched (get dest-shape :touched #{})]
(loop [attrs (seq (keys ctk/sync-attrs)) (loop [attrs (seq (keys ctk/sync-attrs))
roperations [] roperations []
uoperations []] uoperations '()]
(let [attr (first attrs)] (let [attr (first attrs)]
(if (nil? attr) (if (nil? attr)
@ -1215,15 +1215,15 @@
container container
{:type :reg-objects {:type :reg-objects
:shapes all-parents})) :shapes all-parents}))
(update :undo-changes d/preconj (make-change (update :undo-changes conj (make-change
container container
{:type :mod-obj {:type :mod-obj
:id (:id dest-shape) :id (:id dest-shape)
:operations uoperations})) :operations (vec uoperations)}))
(update :undo-changes conj (make-change (update :undo-changes concat [(make-change
container container
{:type :reg-objects {:type :reg-objects
:shapes all-parents}))))) :shapes all-parents})]))))
(let [roperation {:type :set (let [roperation {:type :set
:attr attr :attr attr
:val (get origin-shape attr) :val (get origin-shape attr)
@ -1242,7 +1242,7 @@
uoperations) uoperations)
(recur (next attrs) (recur (next attrs)
(conj roperations roperation) (conj roperations roperation)
(d/preconj uoperations uoperation))))))))) (conj uoperations uoperation)))))))))
(defn- reposition-shape (defn- reposition-shape
[shape origin-root dest-root] [shape origin-root dest-root]

View file

@ -16,6 +16,7 @@
(def current-project-id (mf/create-context nil)) (def current-project-id (mf/create-context nil))
(def current-page-id (mf/create-context nil)) (def current-page-id (mf/create-context nil))
(def current-file-id (mf/create-context nil)) (def current-file-id (mf/create-context nil))
(def current-vbox (mf/create-context nil))
(def active-frames (mf/create-context nil)) (def active-frames (mf/create-context nil))
(def render-thumbnails (mf/create-context nil)) (def render-thumbnails (mf/create-context nil))

View file

@ -13,6 +13,7 @@
common." common."
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.rect :as grc]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.ui.context :as ctx] [app.main.ui.context :as ctx]
@ -54,7 +55,18 @@
;; frame changes won't affect the rendering frame ;; frame changes won't affect the rendering frame
frame-objects frame-objects
(mf/with-memo [objects] (mf/with-memo [objects]
(cph/objects-by-frame objects))] (cph/objects-by-frame objects))
vbox (mf/use-ctx ctx/current-vbox)
shapes
(mf/with-memo [shapes vbox]
(if (some? vbox)
(->> shapes
(filterv (fn [shape]
(grc/overlaps-rects? vbox (dm/get-prop shape :selrect)))))
shapes))]
[:g {:id (dm/str "shape-" uuid/zero)} [:g {:id (dm/str "shape-" uuid/zero)}
[:& (mf/provider ctx/active-frames) {:value active-frames} [:& (mf/provider ctx/active-frames) {:value active-frames}

View file

@ -88,6 +88,7 @@
(let [shape (unchecked-get props "shape")] (let [shape (unchecked-get props "shape")]
[:& frame-shape {:shape shape :ref node-ref}]))))) [:& frame-shape {:shape shape :ref node-ref}])))))
(defn root-frame-wrapper-factory (defn root-frame-wrapper-factory
[shape-wrapper] [shape-wrapper]
@ -101,9 +102,9 @@
thumbnail? (unchecked-get props "thumbnail?") thumbnail? (unchecked-get props "thumbnail?")
page-id (mf/use-ctx ctx/current-page-id) page-id (mf/use-ctx ctx/current-page-id)
frame-id (:id shape) frame-id (dm/get-prop shape :id)
objects (wsh/lookup-page-objects @st/state) objects (wsh/lookup-page-objects @st/state page-id)
node-ref (mf/use-ref nil) node-ref (mf/use-ref nil)
root-ref (mf/use-ref nil) root-ref (mf/use-ref nil)
@ -129,6 +130,7 @@
on-frame-load on-frame-load
(fns/use-node-store node-ref rendered-ref thumbnail? render-frame?) (fns/use-node-store node-ref rendered-ref thumbnail? render-frame?)
] ]
(fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers) (fdm/use-dynamic-modifiers objects (mf/ref-val node-ref) modifiers)

View file

@ -88,6 +88,8 @@
show-distances? show-distances?
picking-color?]} wglobal picking-color?]} wglobal
vbox' (mf/use-debounce 100 vbox)
;; CONTEXT ;; CONTEXT
page-id (mf/use-ctx ctx/current-page-id) page-id (mf/use-ctx ctx/current-page-id)
@ -323,12 +325,13 @@
:y (:y vbox 0) :y (:y vbox 0)
:fill background}] :fill background}]
[:& (mf/provider ctx/current-vbox) {:value vbox'}
[:& (mf/provider use/include-metadata-ctx) {:value (debug? :show-export-metadata)} [:& (mf/provider use/include-metadata-ctx) {:value (debug? :show-export-metadata)}
[:& (mf/provider embed/context) {:value true} [:& (mf/provider embed/context) {:value true}
;; Render root shape ;; Render root shape
[:& shapes/root-shape {:key page-id [:& shapes/root-shape {:key page-id
:objects base-objects :objects base-objects
:active-frames @active-frames}]]]] :active-frames @active-frames}]]]]]
[:svg.viewport-controls [:svg.viewport-controls
{:xmlns "http://www.w3.org/2000/svg" {:xmlns "http://www.w3.org/2000/svg"

View file

@ -10,19 +10,22 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.pages :as cp] [app.common.pages :as cp]
[app.common.pages.helpers :as cph] [app.common.pages.helpers :as cph]
[app.common.pprint :as pp]
[app.common.schema :as sm]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[beicon.core :as rx] [beicon.core :as rx]
[cljs.pprint :refer [pprint]] [cljs.test :as t]
[cljs.test :as t :include-macros true]
[potok.core :as ptk])) [potok.core :as ptk]))
;; ---- Helpers to manage global events ;; ---- Helpers to manage global events
(defn on-error (defn on-error
[cause] [cause]
(js/console.log "[CAUSE]:" (.-stack cause))
(js/console.log "[DATA]:" (pr-str (ex-data cause)))) (js/console.log "STORE ERROR" (.-stack cause))
(when-let [data (some-> cause ex-data ::sm/explain)]
(pp/pprint (sm/humanize-data data))))
(defn prepare-store (defn prepare-store
"Create a store with the given initial state. Wait until "Create a store with the given initial state. Wait until

View file

@ -1,22 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns frontend-tests.setup
(:require
[cljs.test :as t :include-macros true]))
#_(enable-console-print!)
(defmethod t/report [:cljs.test/default :end-run-tests]
[m]
(if (t/successful? m)
(set! (.-exitCode js/process) 0)
(set! (.-exitCode js/process) 1)))
#_(set! *main-cli-fn*
#(t/run-tests 'frontend-tests.test-snap-data
'frontend-tests.test-simple-math
'frontend-tests.test-range-tree))

View file

@ -0,0 +1,31 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns frontend-tests.setup-test
(:require
[app.common.schema :as sm]
[app.common.pprint :as pp]
[cljs.test :as t]))
(.on js/process "uncaughtException" (fn [cause]
(try
(js/console.log "EE" (.-stack cause))
(when-let [data (some-> cause ex-data ::sm/explain)]
(pp/pprint (sm/humanize-data data)))
(finally
(js/console.log "EXIT")
(.exit js/process -1)))))
(defmethod t/report [:cljs.test/default :end-run-tests]
[m]
(if (t/successful? m)
(set! (.-exitCode js/process) 0)
(set! (.-exitCode js/process) 1)))
#_(set! *main-cli-fn*
#(t/run-tests 'frontend-tests.test-snap-data
'frontend-tests.test-simple-math
'frontend-tests.test-range-tree))

View file

@ -1210,7 +1210,7 @@
(dwl/reset-component (:id instance1)) (dwl/reset-component (:id instance1))
:the/end)))) :the/end))))
;;; === Test update component ====================== ;; === Test update component ======================
(t/deftest test-update-component (t/deftest test-update-component
(t/async done (t/async done

View file

@ -15,9 +15,6 @@
[linked.core :as lks] [linked.core :as lks]
[potok.core :as ptk])) [potok.core :as ptk]))
(.on js/process "uncaughtException" (fn [cause]
(js/console.log "EE" cause)))
(t/use-fixtures :each (t/use-fixtures :each
{:before thp/reset-idmap!}) {:before thp/reset-idmap!})