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:
parent
f79e902762
commit
a3a889339b
3 changed files with 96 additions and 37 deletions
|
@ -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)))
|
||||
|
|
|
@ -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
|
||||
(let [updated-parent (helpers/replace-shapes parent selected id)
|
||||
rchanges [{:type :add-obj
|
||||
:id id
|
||||
:frame-id (:frame-id obj)
|
||||
:obj obj}
|
||||
:frame-id frame-id
|
||||
:obj group-shape}
|
||||
{:type :mod-obj
|
||||
:id frame-id
|
||||
:id parent-id
|
||||
:operations [{:type :set
|
||||
:attr :shapes
|
||||
:val (:shapes frame)}]}]
|
||||
[{:type :del-obj :id id}
|
||||
:val (:shapes updated-parent)}]}]
|
||||
uchanges [{:type :del-obj
|
||||
:id id}
|
||||
{:type :mod-obj
|
||||
:id frame-id
|
||||
:id parent-id
|
||||
:operations [{:type :set
|
||||
:attr :shapes
|
||||
:val (into (:shapes frame) (:shapes obj))}]}])))))))
|
||||
: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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue