mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 18:48:37 -05:00
✨ Detect movements inside a component and not override them
This commit is contained in:
parent
ad4115acc8
commit
71759386c5
4 changed files with 107 additions and 48 deletions
|
@ -457,13 +457,18 @@
|
|||
kw (if (keyword? kw) (name kw) kw)]
|
||||
(keyword (str prefix kw))))
|
||||
|
||||
|
||||
(defn tap
|
||||
"Simpilar to the tap in rxjs but for plain collections"
|
||||
[f coll]
|
||||
(f coll)
|
||||
coll)
|
||||
|
||||
(defn tap-r
|
||||
"Same but with args reversed, for -> threads"
|
||||
[coll f]
|
||||
(f coll)
|
||||
coll)
|
||||
|
||||
(defn map-diff
|
||||
"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
|
||||
|
|
|
@ -408,20 +408,22 @@
|
|||
(let [attr (:attr op)
|
||||
val (:val op)
|
||||
ignore (:ignore-touched op)
|
||||
ignore-geometry (:ignore-geometry op)
|
||||
shape-ref (:shape-ref shape)
|
||||
group (get component-sync-attrs attr)
|
||||
root-name? (and (= group :name-group)
|
||||
(:component-root? 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))
|
||||
(not root-name?)
|
||||
;; FIXME: it's difficult to tell if the geometry changes affect
|
||||
;; an individual shape inside the component, or are for
|
||||
;; the whole component (in which case we shouldn't set
|
||||
;; 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)))
|
||||
(not (and ignore-geometry
|
||||
(and (= group :geometry-group)
|
||||
(not (#{:width :height} attr))))))
|
||||
(->
|
||||
(update :touched cph/set-touched-group group)
|
||||
(dissoc :remote-synced?))
|
||||
|
|
|
@ -34,26 +34,26 @@
|
|||
(defn- generate-operation
|
||||
"Given an object old and new versions and an attribute will append into changes
|
||||
the set and undo operations"
|
||||
[changes attr old new]
|
||||
[changes attr old new ignore-geometry?]
|
||||
(let [old-val (get old attr)
|
||||
new-val (get new attr)]
|
||||
(if (= old-val new-val)
|
||||
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})))))
|
||||
|
||||
(defn- update-shape-changes
|
||||
"Calculate the changes and undos to be done when a function is applied to a
|
||||
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)
|
||||
new-obj (update-fn old-obj)
|
||||
|
||||
attrs (or attrs (d/concat #{} (keys old-obj) (keys new-obj)))
|
||||
|
||||
{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 []}
|
||||
attrs)
|
||||
|
||||
|
@ -72,8 +72,8 @@
|
|||
|
||||
(defn update-shapes
|
||||
([ids f] (update-shapes ids f nil))
|
||||
([ids f {:keys [reg-objects? save-undo? keys]
|
||||
:or {reg-objects? false save-undo? true}}]
|
||||
([ids f {:keys [reg-objects? save-undo? keys ignore-tree]
|
||||
:or {reg-objects? false save-undo? true attrs nil}}]
|
||||
|
||||
(us/assert ::coll-of-uuid ids)
|
||||
(us/assert fn? f)
|
||||
|
@ -90,7 +90,9 @@
|
|||
|
||||
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))
|
||||
(let [reg-objs {:type :reg-objects
|
||||
|
|
|
@ -421,27 +421,72 @@
|
|||
|
||||
;; -- 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
|
||||
[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 [])
|
||||
(map #(get objects %)))
|
||||
|
||||
transformed-shape (when (seq children) ; <- don't calculate it if not needed
|
||||
(gsh/transform-shape
|
||||
(assoc shape :modifiers (select-keys modifiers
|
||||
[:resize-origin
|
||||
:resize-vector]))))
|
||||
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
|
||||
(assoc shape :modifiers (select-keys modifiers
|
||||
[:resize-origin
|
||||
:resize-vector]))))
|
||||
set-child (fn [modif-tree child]
|
||||
(let [child-modifiers (gsh/calc-child-modifiers shape
|
||||
transformed-shape
|
||||
resized-shape
|
||||
child
|
||||
modifiers)]
|
||||
(set-modifiers-recursive modif-tree
|
||||
objects
|
||||
child
|
||||
child-modifiers)))]
|
||||
|
||||
child-modifiers
|
||||
root
|
||||
transformed-root)))]
|
||||
(reduce set-child
|
||||
(update-in modif-tree [(:id shape) :modifiers] #(merge % modifiers))
|
||||
children)))
|
||||
|
@ -460,11 +505,13 @@
|
|||
ids (->> ids (into #{} (remove #(get-in objects [% :blocked] false))))]
|
||||
|
||||
(reduce (fn [state id]
|
||||
(update state :workspace-modifiers
|
||||
#(set-modifiers-recursive %
|
||||
objects
|
||||
(get objects id)
|
||||
modifiers)))
|
||||
(update state :workspace-modifiers
|
||||
#(set-modifiers-recursive %
|
||||
objects
|
||||
(get objects id)
|
||||
modifiers
|
||||
nil
|
||||
nil)))
|
||||
state
|
||||
ids))))))
|
||||
|
||||
|
@ -526,28 +573,31 @@
|
|||
state (if set-modifiers?
|
||||
(ptk/update (set-modifiers ids) 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)
|
||||
(dch/update-shapes
|
||||
ids-with-children
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(merge (get object-modifiers (:id shape)))
|
||||
(gsh/transform-shape)))
|
||||
{:reg-objects? true
|
||||
;; Attributes that can change in the transform. This way we don't have to check
|
||||
;; all the attributes
|
||||
:attrs [:selrect :points
|
||||
:x :y
|
||||
:width :height
|
||||
:content
|
||||
:transform
|
||||
:transform-inverse
|
||||
:rotation
|
||||
:flip-x
|
||||
:flip-y]
|
||||
})
|
||||
ids-with-children
|
||||
(fn [shape]
|
||||
(-> shape
|
||||
(merge (get object-modifiers (:id shape)))
|
||||
(gsh/transform-shape)))
|
||||
{:reg-objects? true
|
||||
:ignore-tree ignore-tree
|
||||
;; Attributes that can change in the transform. This way we don't have to check
|
||||
;; all the attributes
|
||||
:attrs [:selrect :points
|
||||
:x :y
|
||||
:width :height
|
||||
:content
|
||||
:transform
|
||||
:transform-inverse
|
||||
:rotation
|
||||
:flip-x
|
||||
:flip-y]
|
||||
})
|
||||
(clear-local-transform)
|
||||
(dwu/commit-undo-transaction)))))))
|
||||
|
||||
|
@ -577,7 +627,7 @@
|
|||
(fn [objects shape-id]
|
||||
(let [shape (get objects shape-id)
|
||||
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
|
||||
state
|
||||
|
|
Loading…
Add table
Reference in a new issue