Detect movements inside a component and not override them

This commit is contained in:
Andrés Moya 2021-06-10 11:04:11 +02:00 committed by Alonso Torres
parent ad4115acc8
commit 71759386c5
4 changed files with 107 additions and 48 deletions

View file

@ -457,13 +457,18 @@
kw (if (keyword? kw) (name kw) kw)] kw (if (keyword? kw) (name kw) kw)]
(keyword (str prefix kw)))) (keyword (str prefix kw))))
(defn tap (defn tap
"Simpilar to the tap in rxjs but for plain collections" "Simpilar to the tap in rxjs but for plain collections"
[f coll] [f coll]
(f coll) (f coll)
coll) coll)
(defn tap-r
"Same but with args reversed, for -> threads"
[coll f]
(f coll)
coll)
(defn map-diff (defn map-diff
"Given two maps returns the diff of its attributes in a map where "Given two maps returns the diff of its attributes in a map where
the keys will be the attributes that change and the values the previous the keys will be the attributes that change and the values the previous

View file

@ -408,20 +408,22 @@
(let [attr (:attr op) (let [attr (:attr op)
val (:val op) val (:val op)
ignore (:ignore-touched op) ignore (:ignore-touched op)
ignore-geometry (:ignore-geometry op)
shape-ref (:shape-ref shape) shape-ref (:shape-ref shape)
group (get component-sync-attrs attr) group (get component-sync-attrs attr)
root-name? (and (= group :name-group) root-name? (and (= group :name-group)
(:component-root? shape))] (:component-root? shape))]
(cond-> shape (cond-> shape
;; Depending on the origin of the attribute change, we need or not to
;; set the "touched" flag for the group the attribute belongs to.
;; In some cases we need to ignore touched only if the attribute is
;; geometric (position, width or transformation).
(and shape-ref group (not ignore) (not= val (get shape attr)) (and shape-ref group (not ignore) (not= val (get shape attr))
(not root-name?) (not root-name?)
;; FIXME: it's difficult to tell if the geometry changes affect (not (and ignore-geometry
;; an individual shape inside the component, or are for (and (= group :geometry-group)
;; the whole component (in which case we shouldn't set (not (#{:width :height} attr))))))
;; touched). For the moment we disable geometry touched
;; except width and height that seems to work well.
(or (not= group :geometry-group) (#{:width :height} attr)))
(-> (->
(update :touched cph/set-touched-group group) (update :touched cph/set-touched-group group)
(dissoc :remote-synced?)) (dissoc :remote-synced?))

View file

@ -34,26 +34,26 @@
(defn- generate-operation (defn- generate-operation
"Given an object old and new versions and an attribute will append into changes "Given an object old and new versions and an attribute will append into changes
the set and undo operations" the set and undo operations"
[changes attr old new] [changes attr old new ignore-geometry?]
(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) (if (= old-val new-val)
changes changes
(-> changes (-> changes
(update :rops conj {:type :set :attr attr :val new-val}) (update :rops conj {:type :set :attr attr :val new-val :ignore-geometry ignore-geometry?})
(update :uops conj {:type :set :attr attr :val old-val :ignore-touched true}))))) (update :uops conj {:type :set :attr attr :val old-val :ignore-touched true})))))
(defn- update-shape-changes (defn- update-shape-changes
"Calculate the changes and undos to be done when a function is applied to a "Calculate the changes and undos to be done when a function is applied to a
single object" single object"
[changes page-id objects update-fn attrs id] [changes page-id objects update-fn attrs id ignore-geometry?]
(let [old-obj (get objects id) (let [old-obj (get objects id)
new-obj (update-fn old-obj) new-obj (update-fn old-obj)
attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj))) attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj)))
{rops :rops uops :uops} {rops :rops uops :uops}
(reduce #(generate-operation %1 %2 old-obj new-obj) (reduce #(generate-operation %1 %2 old-obj new-obj ignore-geometry?)
{:rops [] :uops []} {:rops [] :uops []}
attrs) attrs)
@ -72,8 +72,8 @@
(defn update-shapes (defn update-shapes
([ids f] (update-shapes ids f nil)) ([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects? save-undo? keys] ([ids f {:keys [reg-objects? save-undo? keys ignore-tree]
:or {reg-objects? false save-undo? true}}] :or {reg-objects? false save-undo? true attrs nil}}]
(us/assert ::coll-of-uuid ids) (us/assert ::coll-of-uuid ids)
(us/assert fn? f) (us/assert fn? f)
@ -90,7 +90,9 @@
ids (into [] (filter some?) ids) ids (into [] (filter some?) ids)
changes (reduce #(update-shape-changes %1 page-id objects f keys %2) changes ids)] changes (reduce
#(update-shape-changes %1 page-id objects f keys %2 (get ignore-tree %2))
changes ids)]
(when-not (empty? (:redo-changes changes)) (when-not (empty? (:redo-changes changes))
(let [reg-objs {:type :reg-objects (let [reg-objs {:type :reg-objects

View file

@ -421,27 +421,72 @@
;; -- Apply modifiers ;; -- Apply modifiers
(defn- check-delta
"If the shape is a component instance, check its relative position respect the
root of the component, and see if it changes after applying a transformation."
[shape root transformed-shape transformed-root objects]
(let [root (cond
(:component-root? shape)
shape
(nil? root)
(cp/get-root-shape shape objects)
:else root)
transformed-root (cond
(:component-root? transformed-shape)
transformed-shape
(nil? transformed-root)
(cp/get-root-shape transformed-shape objects)
:else transformed-root)
shape-delta (when root
(gpt/point (- (:x shape) (:x root))
(- (:y shape) (:y root))))
transformed-shape-delta (when transformed-root
(gpt/point (- (:x transformed-shape) (:x transformed-root))
(- (:y transformed-shape) (:y transformed-root))))
ignore-geometry? (= shape-delta transformed-shape-delta)]
[root transformed-root ignore-geometry?]))
(defn- set-modifiers-recursive (defn- set-modifiers-recursive
[modif-tree objects shape modifiers] "Apply the modifiers to one shape, and the corresponding ones to all children,
depending on the child constraints. The modifiers are not directly applied to
the objects tree, but to a separated structure (modif-tree), that may be
merged later with the real objects."
[modif-tree objects shape modifiers root transformed-root]
(let [children (->> (get shape :shapes []) (let [children (->> (get shape :shapes [])
(map #(get objects %))) (map #(get objects %)))
transformed-shape (when (seq children) ; <- don't calculate it if not needed transformed-shape (gsh/transform-shape (assoc shape :modifiers modifiers))
[root transformed-root ignore-geometry?]
(check-delta shape root transformed-shape transformed-root objects)
modifiers (assoc modifiers :ignore-geometry? ignore-geometry?)
resized-shape (when (seq children) ; <- don't calculate it if not needed
(gsh/transform-shape (gsh/transform-shape
(assoc shape :modifiers (select-keys modifiers (assoc shape :modifiers (select-keys modifiers
[:resize-origin [:resize-origin
:resize-vector])))) :resize-vector]))))
set-child (fn [modif-tree child] set-child (fn [modif-tree child]
(let [child-modifiers (gsh/calc-child-modifiers shape (let [child-modifiers (gsh/calc-child-modifiers shape
transformed-shape resized-shape
child child
modifiers)] modifiers)]
(set-modifiers-recursive modif-tree (set-modifiers-recursive modif-tree
objects objects
child child
child-modifiers)))] child-modifiers
root
transformed-root)))]
(reduce set-child (reduce set-child
(update-in modif-tree [(:id shape) :modifiers] #(merge % modifiers)) (update-in modif-tree [(:id shape) :modifiers] #(merge % modifiers))
children))) children)))
@ -464,7 +509,9 @@
#(set-modifiers-recursive % #(set-modifiers-recursive %
objects objects
(get objects id) (get objects id)
modifiers))) modifiers
nil
nil)))
state state
ids)))))) ids))))))
@ -526,7 +573,9 @@
state (if set-modifiers? state (if set-modifiers?
(ptk/update (set-modifiers ids) state) (ptk/update (set-modifiers ids) state)
state) state)
object-modifiers (get state :workspace-modifiers)] object-modifiers (get state :workspace-modifiers)
ignore-tree (d/mapm #(get-in %2 [:modifiers :ignore-geometry?]) object-modifiers)]
(rx/of (dwu/start-undo-transaction) (rx/of (dwu/start-undo-transaction)
(dch/update-shapes (dch/update-shapes
@ -536,6 +585,7 @@
(merge (get object-modifiers (:id shape))) (merge (get object-modifiers (:id shape)))
(gsh/transform-shape))) (gsh/transform-shape)))
{:reg-objects? true {:reg-objects? true
:ignore-tree ignore-tree
;; Attributes that can change in the transform. This way we don't have to check ;; Attributes that can change in the transform. This way we don't have to check
;; all the attributes ;; all the attributes
:attrs [:selrect :points :attrs [:selrect :points
@ -577,7 +627,7 @@
(fn [objects shape-id] (fn [objects shape-id]
(let [shape (get objects shape-id) (let [shape (get objects shape-id)
modifier (gsh/resize-modifiers shape attr value)] modifier (gsh/resize-modifiers shape attr value)]
(set-modifiers-recursive objects objects shape modifier)))] (set-modifiers-recursive objects objects shape modifier nil nil)))]
(d/update-in-when (d/update-in-when
state state