0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-12 07:41:43 -05:00

🎉 Control when the mask of a group is moved or deleted

This commit is contained in:
Andrés Moya 2020-10-19 15:47:59 +02:00 committed by Alonso Torres
parent f9c45849c8
commit 4be7f054b7
4 changed files with 167 additions and 88 deletions

View file

@ -749,7 +749,6 @@
(d/update-in-when data [:pages-index page-id :objects] reg-objects))) (d/update-in-when data [:pages-index page-id :objects] reg-objects)))
(defmethod process-change :mov-objects (defmethod process-change :mov-objects
[data {:keys [parent-id shapes index page-id] :as change}] [data {:keys [parent-id shapes index page-id] :as change}]
(letfn [(is-valid-move? [objects shape-id] (letfn [(is-valid-move? [objects shape-id]
@ -761,12 +760,19 @@
(let [prev-shapes (or prev-shapes [])] (let [prev-shapes (or prev-shapes [])]
(if index (if index
(cph/insert-at-index prev-shapes index shapes) (cph/insert-at-index prev-shapes index shapes)
(reduce (fn [acc id] (cph/append-at-the-end prev-shapes shapes))))
(if (some #{id} acc)
acc (check-insert-items [prev-shapes parent index shapes]
(conj acc id))) (if-not (:masked-group? parent)
prev-shapes (insert-items prev-shapes index shapes)
shapes)))) ;; For masked groups, the first shape is the mask
;; and it cannot be moved.
(let [mask-id (first prev-shapes)
other-ids (rest prev-shapes)
not-mask-shapes (strip-id shapes mask-id)
new-index (if (nil? index) nil (max (dec index) 0))
new-shapes (insert-items other-ids new-index not-mask-shapes)]
(d/concat [mask-id] new-shapes))))
(strip-id [coll id] (strip-id [coll id]
(filterv #(not= % id) coll)) (filterv #(not= % id) coll))
@ -789,7 +795,6 @@
(dissoc objects pid)) (dissoc objects pid))
(update-in objects [pid :shapes] strip-id sid))))))) (update-in objects [pid :shapes] strip-id sid)))))))
(update-parent-id [objects id] (update-parent-id [objects id]
(update objects id assoc :parent-id parent-id)) (update objects id assoc :parent-id parent-id))
@ -820,7 +825,7 @@
(if valid? (if valid?
(as-> objects $ (as-> objects $
(update-in $ [parent-id :shapes] insert-items index shapes) (update-in $ [parent-id :shapes] check-insert-items parent index shapes)
(reduce update-parent-id $ shapes) (reduce update-parent-id $ shapes)
(reduce (partial remove-from-old-parent cpindex) $ shapes) (reduce (partial remove-from-old-parent cpindex) $ shapes)
(reduce (partial update-frame-ids frm-id) $ (get-in $ [parent-id :shapes]))) (reduce (partial update-frame-ids frm-id) $ (get-in $ [parent-id :shapes])))

View file

@ -116,6 +116,15 @@
ids ids
(remove p? after)))) (remove p? after))))
(defn append-at-the-end
[prev-ids ids]
(reduce (fn [acc id]
(if (some #{id} acc)
acc
(conj acc id)))
prev-ids
ids))
(defn select-toplevel-shapes (defn select-toplevel-shapes
([objects] (select-toplevel-shapes objects nil)) ([objects] (select-toplevel-shapes objects nil))
([objects {:keys [include-frames?] :or {include-frames? false}}] ([objects {:keys [include-frames?] :or {include-frames? false}}]

View file

@ -677,10 +677,8 @@
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (dwc/lookup-page-objects state page-id) objects (dwc/lookup-page-objects state page-id)
del-change #(array-map :type :del-obj :page-id page-id :id %)
get-empty-parents get-empty-parents
(fn get-empty-parents [parents] (fn [parents]
(->> parents (->> parents
(map (fn [id] (map (fn [id]
(let [obj (get objects id)] (let [obj (get objects id)]
@ -690,10 +688,29 @@
(take-while (complement nil?)) (take-while (complement nil?))
(map :id))) (map :id)))
groups-to-unmask
(reduce (fn [group-ids id]
;; When the shape to delete is the mask of a masked group,
;; the mask condition must be removed, and it must be
;; converted to a normal group.
(let [obj (get objects id)
parent (get objects (:parent-id obj))]
(if (and (:masked-group? parent)
(= id (first (:shapes parent))))
(conj group-ids (:id parent))
group-ids)))
#{}
ids)
rchanges rchanges
(d/concat
(reduce (fn [res id] (reduce (fn [res id]
(let [children (cph/get-children id objects) (let [children (cph/get-children id objects)
parents (cph/get-parents id objects)] parents (cph/get-parents id objects)
del-change #(array-map
:type :del-obj
:page-id page-id
:id %)]
(d/concat res (d/concat res
(map del-change (reverse children)) (map del-change (reverse children))
[(del-change id)] [(del-change id)]
@ -703,12 +720,21 @@
:shapes (vec parents)}]))) :shapes (vec parents)}])))
[] []
ids) ids)
(map #(array-map
:type :mod-obj
:page-id page-id
:id %
:operations [{:type :set
:attr :masked-group?
:val false}])
groups-to-unmask))
uchanges uchanges
(d/concat
(reduce (fn [res id] (reduce (fn [res id]
(let [children (cph/get-children id objects) (let [children (cph/get-children id objects)
parents (cph/get-parents id objects) parents (cph/get-parents id objects)
add-chg (fn [id] add-change (fn [id]
(let [item (get objects id)] (let [item (get objects id)]
{:type :add-obj {:type :add-obj
:id (:id item) :id (:id item)
@ -718,15 +744,22 @@
:parent-id (:parent-id item) :parent-id (:parent-id item)
:obj item}))] :obj item}))]
(d/concat res (d/concat res
(map add-chg (reverse (get-empty-parents parents))) (map add-change (reverse (get-empty-parents parents)))
[(add-chg id)] [(add-change id)]
(map add-chg children) (map add-change children)
[{:type :reg-objects [{:type :reg-objects
:page-id page-id :page-id page-id
:shapes (vec parents)}]))) :shapes (vec parents)}])))
[] []
ids) ids)
] (map #(array-map
:type :mod-obj
:page-id page-id
:id %
:operations [{:type :set
:attr :masked-group?
:val true}])
groups-to-unmask))]
;; (println "================ rchanges") ;; (println "================ rchanges")
;; (cljs.pprint/pprint rchanges) ;; (cljs.pprint/pprint rchanges)
@ -808,7 +841,23 @@
(conj res (cph/get-parent (first ids) objects)) (conj res (cph/get-parent (first ids) objects))
(next ids)))) (next ids))))
rchanges [{:type :mov-objects groups-to-unmask
(reduce (fn [group-ids id]
;; When a masked group loses its mask shape, because it's
;; moved outside the group, the mask condition must be
;; removed, and it must be converted to a normal group.
(let [obj (get objects id)
parent (get objects (:parent-id obj))]
(if (and (:masked-group? parent)
(= id (first (:shapes parent)))
(not= (:id parent) parent-id))
(conj group-ids (:id parent))
group-ids)))
#{}
ids)
rchanges (d/concat
[{:type :mov-objects
:parent-id parent-id :parent-id parent-id
:page-id page-id :page-id page-id
:index to-index :index to-index
@ -816,8 +865,16 @@
{:type :reg-objects {:type :reg-objects
:page-id page-id :page-id page-id
:shapes parents}] :shapes parents}]
(map (fn [group-id]
{:type :mod-obj
:page-id page-id
:id group-id
:operations [{:type :set
:attr :masked-group?
:val false}]})
groups-to-unmask))
uchanges uchanges (d/concat
(reduce (fn [res id] (reduce (fn [res id]
(let [obj (get objects id)] (let [obj (get objects id)]
(conj res (conj res
@ -827,10 +884,17 @@
:index (cph/position-on-parent id objects) :index (cph/position-on-parent id objects)
:shapes [id]}))) :shapes [id]})))
[] (reverse ids)) [] (reverse ids))
uchanges (conj uchanges [{:type :reg-objects
{:type :reg-objects
:page-id page-id :page-id page-id
:shapes parents})] :shapes parents}]
(map (fn [group-id]
{:type :mod-obj
:page-id page-id
:id group-id
:operations [{:type :set
:attr :masked-group?
:val true}]})
groups-to-unmask))]
;; (println "================ rchanges") ;; (println "================ rchanges")
;; (cljs.pprint/pprint rchanges) ;; (cljs.pprint/pprint rchanges)
@ -1577,9 +1641,10 @@
"+" #(st/emit! (increase-zoom nil)) "+" #(st/emit! (increase-zoom nil))
"-" #(st/emit! (decrease-zoom nil)) "-" #(st/emit! (decrease-zoom nil))
"ctrl+g" #(st/emit! group-selected) "ctrl+g" #(st/emit! group-selected)
"ctrl+shift+m" #(st/emit! mask-group)
"ctrl+k" #(st/emit! dwl/add-component)
"shift+g" #(st/emit! ungroup-selected) "shift+g" #(st/emit! ungroup-selected)
"ctrl+m" #(st/emit! mask-group)
"shift+m" #(st/emit! unmask-group)
"ctrl+k" #(st/emit! dwl/add-component)
"shift+0" #(st/emit! reset-zoom) "shift+0" #(st/emit! reset-zoom)
"shift+1" #(st/emit! zoom-to-fit-all) "shift+1" #(st/emit! zoom-to-fit-all)
"shift+2" #(st/emit! zoom-to-selected-shape) "shift+2" #(st/emit! zoom-to-selected-shape)

View file

@ -105,7 +105,7 @@
:shortcut "Ctrl + g" :shortcut "Ctrl + g"
:on-click do-create-group}] :on-click do-create-group}]
[:& menu-entry {:title "Mask" [:& menu-entry {:title "Mask"
:shortcut "Ctrl + Shift + M" :shortcut "Ctrl + M"
:on-click do-mask-group}]]) :on-click do-mask-group}]])
(when (and (= (count selected) 1) (= (:type shape) :group)) (when (and (= (count selected) 1) (= (:type shape) :group))
@ -115,10 +115,10 @@
:on-click do-remove-group}] :on-click do-remove-group}]
(if (:masked-group? shape) (if (:masked-group? shape)
[:& menu-entry {:title "Unmask" [:& menu-entry {:title "Unmask"
:shortcut "Ctrl + Shift + M" :shortcut "Shift + M"
:on-click do-unmask-group}] :on-click do-unmask-group}]
[:& menu-entry {:title "Mask" [:& menu-entry {:title "Mask"
:shortcut "Ctrl + Shift + M" :shortcut "Ctrl + M"
:on-click do-mask-group}])]) :on-click do-mask-group}])])
(if (:hidden shape) (if (:hidden shape)