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

Adds ungroup shapes

This commit is contained in:
alonso.torres 2020-04-06 11:43:37 +02:00
parent f79e902762
commit a3a889339b
3 changed files with 96 additions and 37 deletions

View file

@ -27,3 +27,43 @@
shapes (remove #(= (:type %) :frame) (vals objects))]
(some contains-shape-fn shapes)))
(defn get-parent
"Retrieve the id of the parent for the shape-id (if exists"
[shape-id objects]
(let [check-parenthood
(fn [shape] (when (and (:shapes shape)
((set (:shapes shape)) shape-id))
(:id shape)))]
(some check-parenthood (vals objects))))
(defn replace-shapes
"Replace inside shapes the value `to-replace-id` for the value in items keeping the same order.
`to-replace-id` can be a set, a sequable or a single value. Any of these will be changed into a
set to make the replacement"
[shape to-replace-id items]
(let [should-replace
(cond
(set? to-replace-id) to-replace-id
(seqable? to-replace-id) (set to-replace-id)
:else #{to-replace-id})
;; This function replaces the first ocurrence of the set `should-replace` for the
;; value in `items`. Next elements that match are removed but not replaced again
;; so for example:
;; should-replace = #{2 3 5}
;; (replace-fn [ 1 2 3 4 5] ["a" "b"] [])
;; => [ 1 "a" "b" 4 ]
replace-fn
(fn [to-replace acc shapes]
(if (empty? shapes)
acc
(let [cur (first shapes)
rest (subvec shapes 1)]
(if (should-replace cur)
(recur [] (into acc to-replace) rest)
(recur to-replace (conj acc cur) rest)))))
replace-shapes (partial replace-fn (if (seqable? items) items [items]) [])]
(update shape :shapes replace-shapes)))

View file

@ -2192,52 +2192,71 @@
(defn create-group []
(let [id (uuid/next)]
(ptk/reify ::create-group
ptk/UpdateEvent
(update [_ state]
ptk/WatchEvent
(watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])]
(if (and selected (-> selected count (> 1)))
(if (not-empty selected)
(let [page-id (get-in state [:workspace-page :id])
objects (get-in state [:workspace-data page-id :objects])
parent (get-parent (first selected) (vals objects))
parent-id (:id parent)
selected-objects (map (partial get objects) selected)
selection-rect (geom/selection-rect selected-objects)
frame-id (-> selected-objects first :frame-id)
new-shape (group-shape id frame-id selected selection-rect)
objects-removed (-> objects
(assoc (:id new-shape) new-shape)
(update-in [(:id parent) :shapes]
(fn [shapes] (filter #(not (selected %)) shapes)))
(update-in [(:id parent) :shapes] conj (:id new-shape)))]
(-> state
(assoc-in [:workspace-data page-id :objects] objects-removed )
(assoc-in [:workspace-local :selected] #{(:id new-shape)})))
state)))
group-shape (group-shape id frame-id selected selection-rect)]
ptk/WatchEvent
(watch [_ state stream]
(let [obj (get-in state [:workspace-data (::page-id state) :objects id])
frame-id (:frame-id obj)
frame (get-in state [:workspace-data (::page-id state) :objects frame-id])]
(rx/of (commit-changes [{:type :add-obj
:id id
:frame-id (:frame-id obj)
:obj obj}
{:type :mod-obj
:id frame-id
:operations [{:type :set
:attr :shapes
:val (:shapes frame)}]}]
[{:type :del-obj :id id}
{:type :mod-obj
:id frame-id
:operations [{:type :set
:attr :shapes
:val (into (:shapes frame) (:shapes obj))}]}])))))))
(let [updated-parent (helpers/replace-shapes parent selected id)
rchanges [{:type :add-obj
:id id
:frame-id frame-id
:obj group-shape}
{:type :mod-obj
:id parent-id
:operations [{:type :set
:attr :shapes
:val (:shapes updated-parent)}]}]
uchanges [{:type :del-obj
:id id}
{:type :mod-obj
:id parent-id
:operations [{:type :set
:attr :shapes
:val (:shapes parent)}]}]]
(rx/of (commit-changes rchanges uchanges {:commit-local? true})
(fn [state] (assoc-in state [:workspace-local :selected] #{id})))))
rx/empty))))))
(defn remove-group []
(ptk/reify ::remove-group
ptk/UpdateEvent
(update [_ state] state)))
ptk/WatchEvent
(watch [_ state stream]
(let [selected (get-in state [:workspace-local :selected])
group-id (first selected)
group (get-in state [:workspace-data (::page-id state) :objects group-id])]
(if (and (= (count selected) 1) (= (:type group) :group))
(let [objects (get-in state [:workspace-data (::page-id state) :objects])
parent-id (helpers/get-parent group-id objects)
parent (get objects parent-id)]
(let [changed-parent (helpers/replace-shapes parent group-id (:shapes group))
rchanges [{:type :mod-obj
:id parent-id
:operations [{:type :set :attr :shapes :val (:shapes changed-parent)}]}
;; Need to modify the object otherwise the children will be deleted
{:type :mod-obj
:id group-id
:operations [{:type :set :attr :shapes :val []}]}
{:type :del-obj
:id group-id}]
uchanges [{:type :add-obj
:id group-id
:frame-id (:frame-id group)
:obj group}
{:type :mod-obj
:id parent-id
:operations [{:type :set :attr :shapes :val (:shapes parent)}]}]]
(rx/of (commit-changes rchanges uchanges {:commit-local? true}))))
rx/empty)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shortcuts

View file

@ -91,11 +91,11 @@
:transform (str
"scale(" inv-zoom ", " inv-zoom ") "
"translate(" (* zoom (:x label-pos)) ", " (* zoom (:y label-pos)) ")")
; User may also select the frame with single click in the label
;; User may also select the frame with single click in the label
:on-click on-double-click}
(:name shape)]
[:& (frame-shape shape-wrapper) {:shape shape
:childs childs}]]))))
:childs childs}]])))))
(defn frame-shape [shape-wrapper]
(mf/fnc frame-shape