0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-08 08:09:14 -05:00

🐛 Fix inconsistent handing of shape relocation.

This commit is contained in:
Andrey Antukh 2020-06-15 11:44:51 +02:00 committed by Hirunatan
parent 1dd1b9d987
commit df7092e2d4
6 changed files with 126 additions and 57 deletions

View file

@ -469,39 +469,88 @@
))
(t/deftest process-change-move-objects-regression
(let [shape-2-id (uuid/custom 1 2)
shape-3-id (uuid/custom 1 3)
(t/deftest process-change-mov-objects-regression
(let [shape-1-id (uuid/custom 2 1)
shape-2-id (uuid/custom 2 2)
shape-3-id (uuid/custom 2 3)
frame-id (uuid/custom 1 1)
changes [{:type :add-obj
:id frame-id
:parent-id uuid/zero
:frame-id uuid/zero
:obj {:type :frame
:name "Frame"}}
{:type :add-obj
:frame-id frame-id
:id shape-2-id
:parent-id frame-id
:id shape-1-id
:obj {:type :shape
:name "Shape"}}
:name "Shape 1"}}
{:type :add-obj
:id shape-3-id
:id shape-2-id
:parent-id uuid/zero
:frame-id uuid/zero
:obj {:type :rect
:name "Shape"}}]
:name "Shape 2"}}
{:type :add-obj
:id shape-3-id
:parent-id uuid/zero
:frame-id uuid/zero
:obj {:type :rect
:name "Shape 3"}}
]
data (cp/process-changes cp/default-page-data changes)]
(t/testing "preserve order on multiple shape mov 1"
(let [changes [{:type :mov-objects
:shapes [shape-2-id shape-3-id]
:parent-id uuid/zero
:index 0}]
res (cp/process-changes data changes)]
;; (println "==> BEFORE")
;; (pprint (get-in data [:objects]))
;; (println "==> AFTER")
;; (pprint (get-in res [:objects]))
(t/is (= [frame-id shape-2-id shape-3-id]
(get-in data [:objects uuid/zero :shapes])))
(t/is (= [shape-2-id shape-3-id frame-id]
(get-in res [:objects uuid/zero :shapes])))))
(t/testing "preserve order on multiple shape mov 1"
(let [changes [{:type :mov-objects
:shapes [shape-3-id shape-2-id]
:parent-id uuid/zero
:index 0}]
res (cp/process-changes data changes)]
;; (println "==> BEFORE")
;; (pprint (get-in data [:objects]))
;; (println "==> AFTER")
;; (pprint (get-in res [:objects]))
(t/is (= [frame-id shape-2-id shape-3-id]
(get-in data [:objects uuid/zero :shapes])))
(t/is (= [shape-3-id shape-2-id frame-id]
(get-in res [:objects uuid/zero :shapes])))))
(t/testing "move inside->outside-inside"
(let [changes [{:type :mov-objects
:shapes [shape-3-id]
:shapes [shape-2-id]
:parent-id frame-id}
{:type :mov-objects
:shapes [shape-3-id]
:shapes [shape-2-id]
:parent-id uuid/zero}]
res (cp/process-changes data changes)]
(t/is (= (get-in res [:objects shape-1-id :frame-id])
(get-in data [:objects shape-1-id :frame-id])))
(t/is (= (get-in res [:objects shape-2-id :frame-id])
(get-in data [:objects shape-2-id :frame-id])))
(t/is (= (get-in res [:objects shape-3-id :frame-id])
(get-in data [:objects shape-3-id :frame-id])))))))
(get-in data [:objects shape-2-id :frame-id])))))
))
(t/deftest process-change-move-objects-2
@ -762,6 +811,3 @@
(t/is (= [#uuid "3375ec40-ab24-11ea-b512-b945e8edccf5"]
(get-in res1 [:objects uuid/zero :shapes])))
))

View file

@ -48,10 +48,10 @@
(defn concat
[& colls]
(loop [result (transient (first colls))
colls (rest colls)]
(if (seq colls)
colls (next colls)]
(if colls
(recur (reduce conj! result (first colls))
(rest colls))
(next colls))
(persistent! result))))
(defn enumerate

View file

@ -184,19 +184,16 @@
(defmethod change-spec-impl :add-obj [_]
(s/keys :req-un [::id ::frame-id ::obj]
:opt-un [::session-id ::parent-id]))
:opt-un [::parent-id]))
(defmethod change-spec-impl :mod-obj [_]
(s/keys :req-un [::id ::operations]
:opt-un [::session-id]))
(s/keys :req-un [::id ::operations]))
(defmethod change-spec-impl :del-obj [_]
(s/keys :req-un [::id]
:opt-un [::session-id]))
(s/keys :req-un [::id]))
(defmethod change-spec-impl :reg-obj [_]
(s/keys :req-un [::ids]
:opt-un [::session-id]))
(defmethod change-spec-impl :reg-objects [_]
(s/keys :req-un [::shapes]))
(defmethod change-spec-impl :mov-objects [_]
(s/keys :req-un [::parent-id ::shapes]
@ -356,15 +353,15 @@
(seq shapes) ; Recursive delete all dependend objects
(as-> $ (reduce #(or (process-change %1 {:type :del-obj :id %2}) %1) $ shapes))))))
(defmethod process-change :reg-obj
[data {:keys [ids]}]
(defmethod process-change :reg-objects
[data {:keys [shapes]}]
(let [objects (:objects data)]
(loop [ids ids data data]
(if (seq ids)
(let [item (get objects (first ids))]
(loop [shapes shapes data data]
(if (seq shapes)
(let [item (get objects (first shapes))]
(if (= :group (:type item))
(recur
(rest ids)
(rest shapes)
(update-in data [:objects (:id item)]
(fn [{:keys [shapes] :as obj}]
(let [shapes (->> shapes
@ -381,7 +378,7 @@
(assoc $ :points (geom/shape->points $))
(assoc $ :selrect (geom/points->selrect (:points $)))))
obj)))))
(recur (rest ids) data)))
(recur (rest shapes) data)))
data))))
(defmethod process-change :mov-objects

View file

@ -39,6 +39,15 @@
(when parent-id
(lazy-seq (cons parent-id (get-parents parent-id objects))))))
(defn get-common-parents
[ids objects]
(loop [res (d/ordered-set)
ids (seq ids)]
(if ids
(recur (into res (get-parents (first ids) objects))
(next ids))
res)))
(defn generate-child-parent-index
[objects]
(reduce-kv

View file

@ -659,7 +659,6 @@
objects (get-in state [:workspace-data page-id :objects])
del-change #(array-map :type :del-obj :id %)
reg-change #(array-map :type :reg-obj :id %)
get-empty-parents
(fn get-empty-parents [parents]
@ -680,7 +679,7 @@
(map del-change (reverse children))
[(del-change id)]
(map del-change (get-empty-parents parents))
[{:type :reg-obj :ids parents}])))
[{:type :reg-objects :shapes (vec parents)}])))
[]
ids)
@ -700,7 +699,7 @@
(map add-chg (reverse (get-empty-parents parents)))
[(add-chg id)]
(map add-chg children)
[{:type :reg-obj :ids parents}])))
[{:type :reg-objects :shapes (vec parents)}])))
[]
ids)
]
@ -772,33 +771,51 @@
;; --- Change Shape Order (D&D Ordering)
(defn relocate-shape
[id parent-id to-index]
(us/verify ::us/uuid id)
(defn relocate-shapes
[ids parent-id to-index]
(us/verify (s/coll-of ::us/uuid) ids)
(us/verify ::us/uuid parent-id)
(us/verify number? to-index)
(ptk/reify ::relocate-shape
dwc/IUpdateGroup
(get-ids [_] [id])
ptk/WatchEvent
(watch [_ state stream]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data page-id :objects])
parent (get objects (cph/get-parent id objects))
current-index (d/index-of (:shapes parent) id)
selected (get-in state [:workspace-local :selected])]
(rx/of (dwc/commit-changes [{:type :mov-objects
:parent-id parent-id
:index to-index
:shapes (vec selected)}]
[{:type :mov-objects
:parent-id (:id parent)
:index current-index
:shapes (vec selected)}]
(let [page-id (:current-page-id state)
objects (get-in state [:workspace-data page-id :objects])
parents (cph/get-common-parents ids objects)
rchanges [{:type :mov-objects
:parent-id parent-id
:index to-index
:shapes (vec (reverse ids))}
{:type :reg-objects
:shapes (vec (conj parents parent-id))}]
uchanges
(reduce (fn [res id]
(let [obj (get objects id)]
(conj res
{:type :mov-objects
:parent-id (:parent-id obj)
:index (cph/position-on-parent id objects)
:shapes [id]})))
[] (reverse ids))
uchanges (conj uchanges
{:type :reg-objects
:shapes (vec parents)})]
(rx/of (dwc/commit-changes rchanges uchanges
{:commit-local? true}))))))
(defn relocate-selected-shapes
[parent-id to-index]
(ptk/reify ::relocate-selected-shapes
ptk/WatchEvent
(watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])]
(rx/of (relocate-shapes selected parent-id to-index))))))
;; --- Change Page Order (D&D Ordering)
(defn relocate-page

View file

@ -163,10 +163,10 @@
on-drop
(fn [side {:keys [id] :as data}]
(if (= side :center)
(st/emit! (dw/relocate-shape id (:id item) 0))
(st/emit! (dw/relocate-selected-shapes (:id item) 0))
(let [to-index (if (= side :top) (inc index) index)
parent-id (cph/get-parent (:id item) objects)]
(st/emit! (dw/relocate-shape id parent-id to-index)))))
(st/emit! (dw/relocate-selected-shapes parent-id to-index)))))
on-hold
(fn []